Merge commit 'c688b5ad5f45f8fe47a2e941fc99b07c950befcc'

This commit is contained in:
Ali 2023-11-16 17:29:44 +04:00
commit 0483060cfb
18 changed files with 813 additions and 162 deletions

View File

@ -10491,3 +10491,9 @@ Sorry for the inconvenience.";
"Premium.Wallpaper.Proceed" = "About Telegram Premium"; "Premium.Wallpaper.Proceed" = "About Telegram Premium";
"Notification.YouChangedWallpaperBoth" = "You set a new wallpaper for %@ and you."; "Notification.YouChangedWallpaperBoth" = "You set a new wallpaper for %@ and you.";
"Stats.ReactionsByEmotionTitle" = "REACTIONS BY EMOTION";
"Stats.StoryInteractionsTitle" = "STORIES INTERACTIONS";
"Stats.StoryReactionsByEmotionTitle" = "STORIES REACTIONS BY EMOTION";
"Stats.MessageReactionsTitle" = "REACTIONS";

View File

@ -32,7 +32,7 @@ class ChartVisibilityItemView: UIView {
func setupView() { func setupView() {
checkButton.frame = bounds checkButton.frame = bounds
checkButton.titleLabel?.font = ChartVisibilityItemView.textFont checkButton.titleLabel?.font = ChartVisibilityItemView.textFont
checkButton.layer.cornerRadius = 6 checkButton.layer.cornerRadius = 15
checkButton.layer.masksToBounds = true checkButton.layer.masksToBounds = true
checkButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside) checkButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
let pressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(didRecognizedLongPress(recognizer:))) let pressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(didRecognizedLongPress(recognizer:)))

View File

@ -1832,6 +1832,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
guard let self else { guard let self else {
return return
} }
let items = items.filter { $0.count > 0 }
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?
let content: ContextControllerItemsContent = MediaGroupsContextMenuContent( let content: ContextControllerItemsContent = MediaGroupsContextMenuContent(
context: self.context, context: self.context,

View File

@ -156,8 +156,9 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
} }
self.doneButtonSolidBackgroundNode.frame = bounds self.doneButtonSolidBackgroundNode.frame = bounds
let constrainedSize = CGSize(width: size.width - 44.0, height: size.height)
let iconSize = CGSize(width: 30.0, height: 30.0) let iconSize = CGSize(width: 30.0, height: 30.0)
let doneTitleSize = self.doneButtonTitleNode.updateLayout(size) let doneTitleSize = self.doneButtonTitleNode.updateLayout(constrainedSize)
var totalWidth = doneTitleSize.width var totalWidth = doneTitleSize.width
if self.isLocked { if self.isLocked {
@ -168,7 +169,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
self.animationNode.frame = CGRect(origin: CGPoint(x: titleOriginX, y: floorToScreenPixels((bounds.height - iconSize.height) / 2.0)), size: iconSize) self.animationNode.frame = CGRect(origin: CGPoint(x: titleOriginX, y: floorToScreenPixels((bounds.height - iconSize.height) / 2.0)), size: iconSize)
self.doneButtonTitleNode.frame = CGRect(origin: CGPoint(x: titleOriginX + totalWidth - doneTitleSize.width, y: floorToScreenPixels((bounds.height - doneTitleSize.height) / 2.0)), size: doneTitleSize).offsetBy(dx: bounds.minX, dy: bounds.minY) self.doneButtonTitleNode.frame = CGRect(origin: CGPoint(x: titleOriginX + totalWidth - doneTitleSize.width, y: floorToScreenPixels((bounds.height - doneTitleSize.height) / 2.0)), size: doneTitleSize).offsetBy(dx: bounds.minX, dy: bounds.minY)
let _ = self.doneButtonSolidTitleNode.updateLayout(size) let _ = self.doneButtonSolidTitleNode.updateLayout(constrainedSize)
self.doneButtonSolidTitleNode.frame = self.doneButtonTitleNode.frame self.doneButtonSolidTitleNode.frame = self.doneButtonTitleNode.frame
self.doneButton.frame = bounds self.doneButton.frame = bounds

View File

@ -62,8 +62,11 @@ private enum StatsSection: Int32 {
case followersBySource case followersBySource
case languages case languages
case postInteractions case postInteractions
case recentPosts
case instantPageInteractions case instantPageInteractions
case reactionsByEmotion
case storyInteractions
case storyReactionsByEmotion
case recentPosts
case boostLevel case boostLevel
case boostOverview case boostOverview
case boostPrepaid case boostPrepaid
@ -99,13 +102,22 @@ private enum StatsEntry: ItemListNodeEntry {
case postInteractionsTitle(PresentationTheme, String) case postInteractionsTitle(PresentationTheme, String)
case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType) case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case reactionsByEmotionTitle(PresentationTheme, String)
case reactionsByEmotionGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case postsTitle(PresentationTheme, String) case storyInteractionsTitle(PresentationTheme, String)
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Message, ChannelStatsMessageInteractions) case storyInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case storyReactionsByEmotionTitle(PresentationTheme, String)
case storyReactionsByEmotionGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case instantPageInteractionsTitle(PresentationTheme, String) case instantPageInteractionsTitle(PresentationTheme, String)
case instantPageInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType) case instantPageInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case postsTitle(PresentationTheme, String)
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Message, ChannelStatsMessageInteractions)
case boostLevel(PresentationTheme, Int32, Int32, CGFloat) case boostLevel(PresentationTheme, Int32, Int32, CGFloat)
case boostOverviewTitle(PresentationTheme, String) case boostOverviewTitle(PresentationTheme, String)
@ -149,10 +161,16 @@ private enum StatsEntry: ItemListNodeEntry {
return StatsSection.languages.rawValue return StatsSection.languages.rawValue
case .postInteractionsTitle, .postInteractionsGraph: case .postInteractionsTitle, .postInteractionsGraph:
return StatsSection.postInteractions.rawValue return StatsSection.postInteractions.rawValue
case .postsTitle, .post:
return StatsSection.recentPosts.rawValue
case .instantPageInteractionsTitle, .instantPageInteractionsGraph: case .instantPageInteractionsTitle, .instantPageInteractionsGraph:
return StatsSection.instantPageInteractions.rawValue return StatsSection.instantPageInteractions.rawValue
case .reactionsByEmotionTitle, .reactionsByEmotionGraph:
return StatsSection.reactionsByEmotion.rawValue
case .storyInteractionsTitle, .storyInteractionsGraph:
return StatsSection.storyInteractions.rawValue
case .storyReactionsByEmotionTitle, .storyReactionsByEmotionGraph:
return StatsSection.storyReactionsByEmotion.rawValue
case .postsTitle, .post:
return StatsSection.recentPosts.rawValue
case .boostLevel: case .boostLevel:
return StatsSection.boostLevel.rawValue return StatsSection.boostLevel.rawValue
case .boostOverviewTitle, .boostOverview: case .boostOverviewTitle, .boostOverview:
@ -207,13 +225,25 @@ private enum StatsEntry: ItemListNodeEntry {
case .postInteractionsGraph: case .postInteractionsGraph:
return 17 return 17
case .instantPageInteractionsTitle: case .instantPageInteractionsTitle:
return 18 return 18
case .instantPageInteractionsGraph: case .instantPageInteractionsGraph:
return 19 return 19
case .postsTitle: case .reactionsByEmotionTitle:
return 20 return 20
case .reactionsByEmotionGraph:
return 21
case .storyInteractionsTitle:
return 22
case .storyInteractionsGraph:
return 23
case .storyReactionsByEmotionTitle:
return 24
case .storyReactionsByEmotionGraph:
return 25
case .postsTitle:
return 26
case let .post(index, _, _, _, _, _): case let .post(index, _, _, _, _, _):
return 21 + index return 27 + index
case .boostLevel: case .boostLevel:
return 2000 return 2000
case .boostOverviewTitle: case .boostOverviewTitle:
@ -367,12 +397,6 @@ private enum StatsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .post(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsMessage, lhsInteractions):
if case let .post(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsMessage, rhsInteractions) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsMessage.id == rhsMessage.id, lhsInteractions == rhsInteractions {
return true
} else {
return false
}
case let .instantPageInteractionsTitle(lhsTheme, lhsText): case let .instantPageInteractionsTitle(lhsTheme, lhsText):
if case let .instantPageInteractionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .instantPageInteractionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -385,6 +409,48 @@ private enum StatsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .reactionsByEmotionTitle(lhsTheme, lhsText):
if case let .reactionsByEmotionTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .reactionsByEmotionGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsType):
if case let .reactionsByEmotionGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsType == rhsType {
return true
} else {
return false
}
case let .storyInteractionsTitle(lhsTheme, lhsText):
if case let .storyInteractionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .storyInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsType):
if case let .storyInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsType == rhsType {
return true
} else {
return false
}
case let .storyReactionsByEmotionTitle(lhsTheme, lhsText):
if case let .storyReactionsByEmotionTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .storyReactionsByEmotionGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsType):
if case let .storyReactionsByEmotionGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsType == rhsType {
return true
} else {
return false
}
case let .post(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsMessage, lhsInteractions):
if case let .post(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsMessage, rhsInteractions) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsMessage.id == rhsMessage.id, lhsInteractions == rhsInteractions {
return true
} else {
return false
}
case let .boostLevel(lhsTheme, lhsBoosts, lhsLevel, lhsPosition): case let .boostLevel(lhsTheme, lhsBoosts, lhsLevel, lhsPosition):
if case let .boostLevel(rhsTheme, rhsBoosts, rhsLevel, rhsPosition) = rhs, lhsTheme === rhsTheme, lhsBoosts == rhsBoosts, lhsLevel == rhsLevel, lhsPosition == rhsPosition { if case let .boostLevel(rhsTheme, rhsBoosts, rhsLevel, rhsPosition) = rhs, lhsTheme === rhsTheme, lhsBoosts == rhsBoosts, lhsLevel == rhsLevel, lhsPosition == rhsPosition {
return true return true
@ -507,8 +573,11 @@ private enum StatsEntry: ItemListNodeEntry {
let .followersBySourceTitle(_, text), let .followersBySourceTitle(_, text),
let .languagesTitle(_, text), let .languagesTitle(_, text),
let .postInteractionsTitle(_, text), let .postInteractionsTitle(_, text),
let .postsTitle(_, text),
let .instantPageInteractionsTitle(_, text), let .instantPageInteractionsTitle(_, text),
let .reactionsByEmotionTitle(_, text),
let .storyInteractionsTitle(_, text),
let .storyReactionsByEmotionTitle(_, text),
let .postsTitle(_, text),
let .boostOverviewTitle(_, text), let .boostOverviewTitle(_, text),
let .boostPrepaidTitle(_, text), let .boostPrepaidTitle(_, text),
let .boostersTitle(_, text), let .boostersTitle(_, text),
@ -527,10 +596,13 @@ private enum StatsEntry: ItemListNodeEntry {
let .viewsByHourGraph(_, _, _, graph, type), let .viewsByHourGraph(_, _, _, graph, type),
let .viewsBySourceGraph(_, _, _, graph, type), let .viewsBySourceGraph(_, _, _, graph, type),
let .followersBySourceGraph(_, _, _, graph, type), let .followersBySourceGraph(_, _, _, graph, type),
let .languagesGraph(_, _, _, graph, type): let .languagesGraph(_, _, _, graph, type),
let .reactionsByEmotionGraph(_, _, _, graph, type),
let .storyReactionsByEmotionGraph(_, _, _, graph, type):
return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, sectionId: self.section, style: .blocks) return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, sectionId: self.section, style: .blocks)
case let .postInteractionsGraph(_, _, _, graph, type), case let .postInteractionsGraph(_, _, _, graph, type),
let .instantPageInteractionsGraph(_, _, _, graph, type): let .instantPageInteractionsGraph(_, _, _, graph, type),
let .storyInteractionsGraph(_, _, _, graph, type):
return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in
let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in
if let graph = graph, case let .Loaded(_, data) = graph { if let graph = graph, case let .Loaded(_, data) = graph {
@ -760,6 +832,21 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
entries.append(.instantPageInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.instantPageInteractionsGraph, .twoAxisStep)) entries.append(.instantPageInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.instantPageInteractionsGraph, .twoAxisStep))
} }
if !data.reactionsByEmotionGraph.isEmpty {
entries.append(.reactionsByEmotionTitle(presentationData.theme, presentationData.strings.Stats_ReactionsByEmotionTitle))
entries.append(.reactionsByEmotionGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.reactionsByEmotionGraph, .bars))
}
if !data.storyInteractionsGraph.isEmpty {
entries.append(.storyInteractionsTitle(presentationData.theme, presentationData.strings.Stats_StoryInteractionsTitle))
entries.append(.storyInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.storyInteractionsGraph, .twoAxisStep))
}
if !data.storyReactionsByEmotionGraph.isEmpty {
entries.append(.storyReactionsByEmotionTitle(presentationData.theme, presentationData.strings.Stats_StoryReactionsByEmotionTitle))
entries.append(.storyReactionsByEmotionGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.storyReactionsByEmotionGraph, .bars))
}
if let messages = messages, !messages.isEmpty, let interactions = interactions, !interactions.isEmpty { if let messages = messages, !messages.isEmpty, let interactions = interactions, !interactions.isEmpty {
entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle)) entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle))
var index: Int32 = 0 var index: Int32 = 0
@ -915,6 +1002,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
statsContext.loadViewsBySourceGraph() statsContext.loadViewsBySourceGraph()
statsContext.loadLanguagesGraph() statsContext.loadLanguagesGraph()
statsContext.loadInstantPageInteractionsGraph() statsContext.loadInstantPageInteractionsGraph()
statsContext.loadReactionsByEmotionGraph()
statsContext.loadStoryInteractionsGraph()
statsContext.loadStoryReactionsByEmotionGraph()
} }
} }
}) })

View File

@ -29,6 +29,7 @@ private final class MessageStatsControllerArguments {
private enum StatsSection: Int32 { private enum StatsSection: Int32 {
case overview case overview
case interactions case interactions
case reactions
case publicForwards case publicForwards
} }
@ -39,6 +40,9 @@ private enum StatsEntry: ItemListNodeEntry {
case interactionsTitle(PresentationTheme, String) case interactionsTitle(PresentationTheme, String)
case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType) case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case reactionsTitle(PresentationTheme, String)
case reactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case publicForwardsTitle(PresentationTheme, String) case publicForwardsTitle(PresentationTheme, String)
case publicForward(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, EngineMessage) case publicForward(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, EngineMessage)
@ -48,6 +52,8 @@ private enum StatsEntry: ItemListNodeEntry {
return StatsSection.overview.rawValue return StatsSection.overview.rawValue
case .interactionsTitle, .interactionsGraph: case .interactionsTitle, .interactionsGraph:
return StatsSection.interactions.rawValue return StatsSection.interactions.rawValue
case .reactionsTitle, .reactionsGraph:
return StatsSection.reactions.rawValue
case .publicForwardsTitle, .publicForward: case .publicForwardsTitle, .publicForward:
return StatsSection.publicForwards.rawValue return StatsSection.publicForwards.rawValue
} }
@ -63,10 +69,14 @@ private enum StatsEntry: ItemListNodeEntry {
return 2 return 2
case .interactionsGraph: case .interactionsGraph:
return 3 return 3
case .publicForwardsTitle: case .reactionsTitle:
return 4 return 4
case .reactionsGraph:
return 5
case .publicForwardsTitle:
return 6
case let .publicForward(index, _, _, _, _): case let .publicForward(index, _, _, _, _):
return 5 + index return 7 + index
} }
} }
@ -96,6 +106,18 @@ private enum StatsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .reactionsTitle(lhsTheme, lhsText):
if case let .reactionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .reactionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsType):
if case let .reactionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsType == rhsType {
return true
} else {
return false
}
case let .publicForwardsTitle(lhsTheme, lhsText): case let .publicForwardsTitle(lhsTheme, lhsText):
if case let .publicForwardsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .publicForwardsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -120,11 +142,12 @@ private enum StatsEntry: ItemListNodeEntry {
switch self { switch self {
case let .overviewTitle(_, text), case let .overviewTitle(_, text),
let .interactionsTitle(_, text), let .interactionsTitle(_, text),
let .reactionsTitle(_, text),
let .publicForwardsTitle(_, text): let .publicForwardsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .overview(_, stats, publicShares): case let .overview(_, stats, publicShares):
return MessageStatsOverviewItem(presentationData: presentationData, stats: stats, publicShares: publicShares, sectionId: self.section, style: .blocks) return MessageStatsOverviewItem(presentationData: presentationData, stats: stats, publicShares: publicShares, sectionId: self.section, style: .blocks)
case let .interactionsGraph(_, _, _, graph, type): case let .interactionsGraph(_, _, _, graph, type), let .reactionsGraph(_, _, _, graph, type):
return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in
let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in
if let graph = graph, case let .Loaded(_, data) = graph { if let graph = graph, case let .Loaded(_, data) = graph {
@ -170,6 +193,11 @@ private func messageStatsControllerEntries(data: MessageStats?, messages: Search
entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, chartType)) entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, chartType))
} }
if !data.reactionsGraph.isEmpty {
entries.append(.reactionsTitle(presentationData.theme, presentationData.strings.Stats_MessageReactionsTitle.uppercased()))
entries.append(.reactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.reactionsGraph, .bars))
}
if let messages = messages, !messages.messages.isEmpty { if let messages = messages, !messages.messages.isEmpty {
entries.append(.publicForwardsTitle(presentationData.theme, presentationData.strings.Stats_MessagePublicForwardsTitle.uppercased())) entries.append(.publicForwardsTitle(presentationData.theme, presentationData.strings.Stats_MessagePublicForwardsTitle.uppercased()))

View File

@ -180,6 +180,7 @@ class StatsGraphItemNode: ListViewItemNode {
if let visibilityHeight = visibilityHeight { if let visibilityHeight = visibilityHeight {
contentSize.height += visibilityHeight contentSize.height += visibilityHeight
} }
contentSize.height += 7.0
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in

View File

@ -817,7 +817,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) } dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) }
dict[2008112412] = { return Api.StickerSetCovered.parse_stickerSetNoCovered($0) } dict[2008112412] = { return Api.StickerSetCovered.parse_stickerSetNoCovered($0) }
dict[1898850301] = { return Api.StoriesStealthMode.parse_storiesStealthMode($0) } dict[1898850301] = { return Api.StoriesStealthMode.parse_storiesStealthMode($0) }
dict[1153718222] = { return Api.StoryItem.parse_storyItem($0) } dict[-1205411504] = { return Api.StoryFwdHeader.parse_storyFwdHeader($0) }
dict[-1352440415] = { return Api.StoryItem.parse_storyItem($0) }
dict[1374088783] = { return Api.StoryItem.parse_storyItemDeleted($0) } dict[1374088783] = { return Api.StoryItem.parse_storyItemDeleted($0) }
dict[-5388013] = { return Api.StoryItem.parse_storyItemSkipped($0) } dict[-5388013] = { return Api.StoryItem.parse_storyItemSkipped($0) }
dict[-1329730875] = { return Api.StoryView.parse_storyView($0) } dict[-1329730875] = { return Api.StoryView.parse_storyView($0) }
@ -1186,9 +1187,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-2030542532] = { return Api.premium.BoostsList.parse_boostsList($0) } dict[-2030542532] = { return Api.premium.BoostsList.parse_boostsList($0) }
dict[1230586490] = { return Api.premium.BoostsStatus.parse_boostsStatus($0) } dict[1230586490] = { return Api.premium.BoostsStatus.parse_boostsStatus($0) }
dict[-1696454430] = { return Api.premium.MyBoosts.parse_myBoosts($0) } dict[-1696454430] = { return Api.premium.MyBoosts.parse_myBoosts($0) }
dict[-1107852396] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-886032030] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) }
dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) } dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) }
dict[-1986399595] = { return Api.stats.MessageStats.parse_messageStats($0) } dict[2145983508] = { return Api.stats.MessageStats.parse_messageStats($0) }
dict[1355613820] = { return Api.stats.StoryStats.parse_storyStats($0) }
dict[-2046910401] = { return Api.stickers.SuggestedShortName.parse_suggestedShortName($0) } dict[-2046910401] = { return Api.stickers.SuggestedShortName.parse_suggestedShortName($0) }
dict[-891180321] = { return Api.storage.FileType.parse_fileGif($0) } dict[-891180321] = { return Api.storage.FileType.parse_fileGif($0) }
dict[8322574] = { return Api.storage.FileType.parse_fileJpeg($0) } dict[8322574] = { return Api.storage.FileType.parse_fileJpeg($0) }
@ -1779,6 +1781,8 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StoriesStealthMode: case let _1 as Api.StoriesStealthMode:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StoryFwdHeader:
_1.serialize(buffer, boxed)
case let _1 as Api.StoryItem: case let _1 as Api.StoryItem:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StoryView: case let _1 as Api.StoryView:
@ -2095,6 +2099,8 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.stats.MessageStats: case let _1 as Api.stats.MessageStats:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.stats.StoryStats:
_1.serialize(buffer, boxed)
case let _1 as Api.stickers.SuggestedShortName: case let _1 as Api.stickers.SuggestedShortName:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.storage.FileType: case let _1 as Api.storage.FileType:

View File

@ -406,21 +406,72 @@ public extension Api {
} }
} }
public extension Api {
enum StoryFwdHeader: TypeConstructorDescription {
case storyFwdHeader(flags: Int32, from: Api.Peer?, fromName: String?, storyId: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyFwdHeader(let flags, let from, let fromName, let storyId):
if boxed {
buffer.appendInt32(-1205411504)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {from!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(fromName!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(storyId!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyFwdHeader(let flags, let from, let fromName, let storyId):
return ("storyFwdHeader", [("flags", flags as Any), ("from", from as Any), ("fromName", fromName as Any), ("storyId", storyId as Any)])
}
}
public static func parse_storyFwdHeader(_ reader: BufferReader) -> StoryFwdHeader? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _3: String?
if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) }
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 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.StoryFwdHeader.storyFwdHeader(flags: _1!, from: _2, fromName: _3, storyId: _4)
}
else {
return nil
}
}
}
}
public extension Api { public extension Api {
indirect enum StoryItem: TypeConstructorDescription { indirect enum StoryItem: TypeConstructorDescription {
case storyItem(flags: Int32, id: Int32, date: Int32, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?) case storyItem(flags: Int32, id: Int32, date: Int32, fwdFrom: Api.StoryFwdHeader?, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?)
case storyItemDeleted(id: Int32) case storyItemDeleted(id: Int32)
case storyItemSkipped(flags: Int32, id: Int32, date: Int32, expireDate: Int32) case storyItemSkipped(flags: Int32, id: Int32, date: Int32, expireDate: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .storyItem(let flags, let id, let date, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction): case .storyItem(let flags, let id, let date, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction):
if boxed { if boxed {
buffer.appendInt32(1153718222) buffer.appendInt32(-1352440415)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 17) != 0 {fwdFrom!.serialize(buffer, true)}
serializeInt32(expireDate, buffer: buffer, boxed: false) serializeInt32(expireDate, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(caption!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(caption!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
@ -462,8 +513,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .storyItem(let flags, let id, let date, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction): case .storyItem(let flags, let id, let date, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction):
return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("expireDate", expireDate as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("mediaAreas", mediaAreas as Any), ("privacy", privacy as Any), ("views", views as Any), ("sentReaction", sentReaction as Any)]) return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("fwdFrom", fwdFrom as Any), ("expireDate", expireDate as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("mediaAreas", mediaAreas as Any), ("privacy", privacy as Any), ("views", views as Any), ("sentReaction", sentReaction as Any)])
case .storyItemDeleted(let id): case .storyItemDeleted(let id):
return ("storyItemDeleted", [("id", id as Any)]) return ("storyItemDeleted", [("id", id as Any)])
case .storyItemSkipped(let flags, let id, let date, let expireDate): case .storyItemSkipped(let flags, let id, let date, let expireDate):
@ -478,47 +529,52 @@ public extension Api {
_2 = reader.readInt32() _2 = reader.readInt32()
var _3: Int32? var _3: Int32?
_3 = reader.readInt32() _3 = reader.readInt32()
var _4: Int32? var _4: Api.StoryFwdHeader?
_4 = reader.readInt32() if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
var _5: String? _4 = Api.parse(reader, signature: signature) as? Api.StoryFwdHeader
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) } } }
var _6: [Api.MessageEntity]? var _5: Int32?
_5 = reader.readInt32()
var _6: String?
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
var _7: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} } } }
var _7: Api.MessageMedia? var _8: Api.MessageMedia?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.MessageMedia _8 = Api.parse(reader, signature: signature) as? Api.MessageMedia
} }
var _8: [Api.MediaArea]? var _9: [Api.MediaArea]?
if Int(_1!) & Int(1 << 14) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 14) != 0 {if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MediaArea.self) _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MediaArea.self)
} } } }
var _9: [Api.PrivacyRule]? var _10: [Api.PrivacyRule]?
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self) _10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self)
} } } }
var _10: Api.StoryViews? var _11: Api.StoryViews?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_10 = Api.parse(reader, signature: signature) as? Api.StoryViews _11 = Api.parse(reader, signature: signature) as? Api.StoryViews
} } } }
var _11: Api.Reaction? var _12: Api.Reaction?
if Int(_1!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.Reaction _12 = Api.parse(reader, signature: signature) as? Api.Reaction
} } } }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = _4 != nil let _c4 = (Int(_1!) & Int(1 << 17) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = _7 != nil let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 14) == 0) || _8 != nil let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 2) == 0) || _9 != nil let _c9 = (Int(_1!) & Int(1 << 14) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 3) == 0) || _10 != nil let _c10 = (Int(_1!) & Int(1 << 2) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 15) == 0) || _11 != nil let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { let _c12 = (Int(_1!) & Int(1 << 15) == 0) || _12 != nil
return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, expireDate: _4!, caption: _5, entities: _6, media: _7!, mediaAreas: _8, privacy: _9, views: _10, sentReaction: _11) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, fwdFrom: _4, expireDate: _5!, caption: _6, entities: _7, media: _8!, mediaAreas: _9, privacy: _10, views: _11, sentReaction: _12)
} }
else { else {
return nil return nil

View File

@ -212,13 +212,13 @@ public extension Api.premium {
} }
public extension Api.stats { public extension Api.stats {
enum BroadcastStats: TypeConstructorDescription { enum BroadcastStats: TypeConstructorDescription {
case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters]) case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph, storyInteractionsGraph: Api.StatsGraph, storyReactionsByEmotionGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentMessageInteractions):
if boxed { if boxed {
buffer.appendInt32(-1107852396) buffer.appendInt32(-886032030)
} }
period.serialize(buffer, true) period.serialize(buffer, true)
followers.serialize(buffer, true) followers.serialize(buffer, true)
@ -234,6 +234,9 @@ public extension Api.stats {
viewsBySourceGraph.serialize(buffer, true) viewsBySourceGraph.serialize(buffer, true)
newFollowersBySourceGraph.serialize(buffer, true) newFollowersBySourceGraph.serialize(buffer, true)
languagesGraph.serialize(buffer, true) languagesGraph.serialize(buffer, true)
reactionsByEmotionGraph.serialize(buffer, true)
storyInteractionsGraph.serialize(buffer, true)
storyReactionsByEmotionGraph.serialize(buffer, true)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentMessageInteractions.count)) buffer.appendInt32(Int32(recentMessageInteractions.count))
for item in recentMessageInteractions { for item in recentMessageInteractions {
@ -245,8 +248,8 @@ public extension Api.stats {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentMessageInteractions):
return ("broadcastStats", [("period", period as Any), ("followers", followers as Any), ("viewsPerPost", viewsPerPost as Any), ("sharesPerPost", sharesPerPost as Any), ("enabledNotifications", enabledNotifications as Any), ("growthGraph", growthGraph as Any), ("followersGraph", followersGraph as Any), ("muteGraph", muteGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("interactionsGraph", interactionsGraph as Any), ("ivInteractionsGraph", ivInteractionsGraph as Any), ("viewsBySourceGraph", viewsBySourceGraph as Any), ("newFollowersBySourceGraph", newFollowersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("recentMessageInteractions", recentMessageInteractions as Any)]) return ("broadcastStats", [("period", period as Any), ("followers", followers as Any), ("viewsPerPost", viewsPerPost as Any), ("sharesPerPost", sharesPerPost as Any), ("enabledNotifications", enabledNotifications as Any), ("growthGraph", growthGraph as Any), ("followersGraph", followersGraph as Any), ("muteGraph", muteGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("interactionsGraph", interactionsGraph as Any), ("ivInteractionsGraph", ivInteractionsGraph as Any), ("viewsBySourceGraph", viewsBySourceGraph as Any), ("newFollowersBySourceGraph", newFollowersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any), ("storyInteractionsGraph", storyInteractionsGraph as Any), ("storyReactionsByEmotionGraph", storyReactionsByEmotionGraph as Any), ("recentMessageInteractions", recentMessageInteractions as Any)])
} }
} }
@ -307,9 +310,21 @@ public extension Api.stats {
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
_14 = Api.parse(reader, signature: signature) as? Api.StatsGraph _14 = Api.parse(reader, signature: signature) as? Api.StatsGraph
} }
var _15: [Api.MessageInteractionCounters]? var _15: Api.StatsGraph?
if let signature = reader.readInt32() {
_15 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _16: Api.StatsGraph?
if let signature = reader.readInt32() {
_16 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _17: Api.StatsGraph?
if let signature = reader.readInt32() {
_17 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _18: [Api.MessageInteractionCounters]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageInteractionCounters.self) _18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageInteractionCounters.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
@ -326,8 +341,11 @@ public extension Api.stats {
let _c13 = _13 != nil let _c13 = _13 != nil
let _c14 = _14 != nil let _c14 = _14 != nil
let _c15 = _15 != nil let _c15 = _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 { let _c16 = _16 != nil
return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, growthGraph: _6!, followersGraph: _7!, muteGraph: _8!, topHoursGraph: _9!, interactionsGraph: _10!, ivInteractionsGraph: _11!, viewsBySourceGraph: _12!, newFollowersBySourceGraph: _13!, languagesGraph: _14!, recentMessageInteractions: _15!) let _c17 = _17 != nil
let _c18 = _18 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 {
return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, growthGraph: _6!, followersGraph: _7!, muteGraph: _8!, topHoursGraph: _9!, interactionsGraph: _10!, ivInteractionsGraph: _11!, viewsBySourceGraph: _12!, newFollowersBySourceGraph: _13!, languagesGraph: _14!, reactionsByEmotionGraph: _15!, storyInteractionsGraph: _16!, storyReactionsByEmotionGraph: _17!, recentMessageInteractions: _18!)
} }
else { else {
return nil return nil
@ -488,23 +506,24 @@ public extension Api.stats {
} }
public extension Api.stats { public extension Api.stats {
enum MessageStats: TypeConstructorDescription { enum MessageStats: TypeConstructorDescription {
case messageStats(viewsGraph: Api.StatsGraph) case messageStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .messageStats(let viewsGraph): case .messageStats(let viewsGraph, let reactionsByEmotionGraph):
if boxed { if boxed {
buffer.appendInt32(-1986399595) buffer.appendInt32(2145983508)
} }
viewsGraph.serialize(buffer, true) viewsGraph.serialize(buffer, true)
reactionsByEmotionGraph.serialize(buffer, true)
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .messageStats(let viewsGraph): case .messageStats(let viewsGraph, let reactionsByEmotionGraph):
return ("messageStats", [("viewsGraph", viewsGraph as Any)]) return ("messageStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)])
} }
} }
@ -513,9 +532,58 @@ public extension Api.stats {
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
} }
var _2: Api.StatsGraph?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
let _c1 = _1 != nil let _c1 = _1 != nil
if _c1 { let _c2 = _2 != nil
return Api.stats.MessageStats.messageStats(viewsGraph: _1!) if _c1 && _c2 {
return Api.stats.MessageStats.messageStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!)
}
else {
return nil
}
}
}
}
public extension Api.stats {
enum StoryStats: TypeConstructorDescription {
case storyStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
if boxed {
buffer.appendInt32(1355613820)
}
viewsGraph.serialize(buffer, true)
reactionsByEmotionGraph.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
return ("storyStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)])
}
}
public static func parse_storyStats(_ reader: BufferReader) -> StoryStats? {
var _1: Api.StatsGraph?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _2: Api.StatsGraph?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.stats.StoryStats.storyStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!)
} }
else { else {
return nil return nil
@ -1478,59 +1546,3 @@ public extension Api.updates {
} }
} }
public extension Api.upload {
enum CdnFile: TypeConstructorDescription {
case cdnFile(bytes: Buffer)
case cdnFileReuploadNeeded(requestToken: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .cdnFile(let bytes):
if boxed {
buffer.appendInt32(-1449145777)
}
serializeBytes(bytes, buffer: buffer, boxed: false)
break
case .cdnFileReuploadNeeded(let requestToken):
if boxed {
buffer.appendInt32(-290921362)
}
serializeBytes(requestToken, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .cdnFile(let bytes):
return ("cdnFile", [("bytes", bytes as Any)])
case .cdnFileReuploadNeeded(let requestToken):
return ("cdnFileReuploadNeeded", [("requestToken", requestToken as Any)])
}
}
public static func parse_cdnFile(_ reader: BufferReader) -> CdnFile? {
var _1: Buffer?
_1 = parseBytes(reader)
let _c1 = _1 != nil
if _c1 {
return Api.upload.CdnFile.cdnFile(bytes: _1!)
}
else {
return nil
}
}
public static func parse_cdnFileReuploadNeeded(_ reader: BufferReader) -> CdnFile? {
var _1: Buffer?
_1 = parseBytes(reader)
let _c1 = _1 != nil
if _c1 {
return Api.upload.CdnFile.cdnFileReuploadNeeded(requestToken: _1!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,59 @@
public extension Api.upload {
enum CdnFile: TypeConstructorDescription {
case cdnFile(bytes: Buffer)
case cdnFileReuploadNeeded(requestToken: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .cdnFile(let bytes):
if boxed {
buffer.appendInt32(-1449145777)
}
serializeBytes(bytes, buffer: buffer, boxed: false)
break
case .cdnFileReuploadNeeded(let requestToken):
if boxed {
buffer.appendInt32(-290921362)
}
serializeBytes(requestToken, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .cdnFile(let bytes):
return ("cdnFile", [("bytes", bytes as Any)])
case .cdnFileReuploadNeeded(let requestToken):
return ("cdnFileReuploadNeeded", [("requestToken", requestToken as Any)])
}
}
public static func parse_cdnFile(_ reader: BufferReader) -> CdnFile? {
var _1: Buffer?
_1 = parseBytes(reader)
let _c1 = _1 != nil
if _c1 {
return Api.upload.CdnFile.cdnFile(bytes: _1!)
}
else {
return nil
}
}
public static func parse_cdnFileReuploadNeeded(_ reader: BufferReader) -> CdnFile? {
var _1: Buffer?
_1 = parseBytes(reader)
let _c1 = _1 != nil
if _c1 {
return Api.upload.CdnFile.cdnFileReuploadNeeded(requestToken: _1!)
}
else {
return nil
}
}
}
}
public extension Api.upload { public extension Api.upload {
enum File: TypeConstructorDescription { enum File: TypeConstructorDescription {
case file(type: Api.storage.FileType, mtime: Int32, bytes: Buffer) case file(type: Api.storage.FileType, mtime: Int32, bytes: Buffer)

View File

@ -8578,6 +8578,23 @@ public extension Api.functions.stats {
}) })
} }
} }
public extension Api.functions.stats {
static func getStoryStats(flags: Int32, peer: Api.InputPeer, id: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stats.StoryStats>) {
let buffer = Buffer()
buffer.appendInt32(927985472)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stats.getStoryStats", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.StoryStats? in
let reader = BufferReader(buffer)
var result: Api.stats.StoryStats?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.stats.StoryStats
}
return result
})
}
}
public extension Api.functions.stats { public extension Api.functions.stats {
static func loadAsyncGraph(flags: Int32, token: String, x: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.StatsGraph>) { static func loadAsyncGraph(flags: Int32, token: String, x: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.StatsGraph>) {
let buffer = Buffer() let buffer = Buffer()
@ -9116,9 +9133,9 @@ public extension Api.functions.stories {
} }
} }
public extension Api.functions.stories { public extension Api.functions.stories {
static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) { static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?, fwdFromId: Api.InputPeer?, fwdFromStory: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-1128843708) buffer.appendInt32(-454661813)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
media.serialize(buffer, true) media.serialize(buffer, true)
@ -9140,7 +9157,9 @@ public extension Api.functions.stories {
} }
serializeInt64(randomId, buffer: buffer, boxed: false) serializeInt64(randomId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 3) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("media", String(describing: media)), ("mediaAreas", String(describing: mediaAreas)), ("caption", String(describing: caption)), ("entities", String(describing: entities)), ("privacyRules", String(describing: privacyRules)), ("randomId", String(describing: randomId)), ("period", String(describing: period))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in if Int(flags) & Int(1 << 6) != 0 {fwdFromId!.serialize(buffer, true)}
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(fwdFromStory!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("media", String(describing: media)), ("mediaAreas", String(describing: mediaAreas)), ("caption", String(describing: caption)), ("entities", String(describing: entities)), ("privacyRules", String(describing: privacyRules)), ("randomId", String(describing: randomId)), ("period", String(describing: period)), ("fwdFromId", String(describing: fwdFromId)), ("fwdFromStory", String(describing: fwdFromStory))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.Updates? var result: Api.Updates?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {

View File

@ -9,12 +9,14 @@ public struct MessageStats: Equatable {
public let forwards: Int public let forwards: Int
public let interactionsGraph: StatsGraph public let interactionsGraph: StatsGraph
public let interactionsGraphDelta: Int64 public let interactionsGraphDelta: Int64
public let reactionsGraph: StatsGraph
init(views: Int, forwards: Int, interactionsGraph: StatsGraph, interactionsGraphDelta: Int64) { init(views: Int, forwards: Int, interactionsGraph: StatsGraph, interactionsGraphDelta: Int64, reactionsGraph: StatsGraph) {
self.views = views self.views = views
self.forwards = forwards self.forwards = forwards
self.interactionsGraph = interactionsGraph self.interactionsGraph = interactionsGraph
self.interactionsGraphDelta = interactionsGraphDelta self.interactionsGraphDelta = interactionsGraphDelta
self.reactionsGraph = reactionsGraph
} }
public static func == (lhs: MessageStats, rhs: MessageStats) -> Bool { public static func == (lhs: MessageStats, rhs: MessageStats) -> Bool {
@ -30,11 +32,14 @@ public struct MessageStats: Equatable {
if lhs.interactionsGraphDelta != rhs.interactionsGraphDelta { if lhs.interactionsGraphDelta != rhs.interactionsGraphDelta {
return false return false
} }
if lhs.reactionsGraph != rhs.reactionsGraph {
return false
}
return true return true
} }
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> MessageStats { public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> MessageStats {
return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: self.interactionsGraphDelta) return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: self.interactionsGraphDelta, reactionsGraph: self.reactionsGraph)
} }
} }
@ -83,8 +88,8 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
return signal return signal
|> mapToSignal { result -> Signal<MessageStats?, MTRpcError> in |> mapToSignal { result -> Signal<MessageStats?, MTRpcError> in
if case let .messageStats(apiViewsGraph) = result { if case let .messageStats(apiInteractionsGraph, apiReactionsGraph) = result {
let interactionsGraph = StatsGraph(apiStatsGraph: apiViewsGraph) let interactionsGraph = StatsGraph(apiStatsGraph: apiInteractionsGraph)
var interactionsGraphDelta: Int64 = 86400 var interactionsGraphDelta: Int64 = 86400
if case let .Loaded(_, data) = interactionsGraph { if case let .Loaded(_, data) = interactionsGraph {
if let start = data.range(of: "[\"x\",") { if let start = data.range(of: "[\"x\",") {
@ -101,8 +106,14 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
} }
} }
} }
let reactionsGraph = StatsGraph(apiStatsGraph: apiReactionsGraph)
return .single(MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: interactionsGraphDelta)) return .single(MessageStats(
views: views,
forwards: forwards,
interactionsGraph: interactionsGraph,
interactionsGraphDelta: interactionsGraphDelta,
reactionsGraph: reactionsGraph
))
} else { } else {
return .single(nil) return .single(nil)
} }

View File

@ -69,9 +69,31 @@ public final class ChannelStats: Equatable {
public let viewsBySourceGraph: StatsGraph public let viewsBySourceGraph: StatsGraph
public let newFollowersBySourceGraph: StatsGraph public let newFollowersBySourceGraph: StatsGraph
public let languagesGraph: StatsGraph public let languagesGraph: StatsGraph
public let reactionsByEmotionGraph: StatsGraph
public let storyInteractionsGraph: StatsGraph
public let storyReactionsByEmotionGraph: StatsGraph
public let messageInteractions: [ChannelStatsMessageInteractions] public let messageInteractions: [ChannelStatsMessageInteractions]
init(period: StatsDateRange, followers: StatsValue, viewsPerPost: StatsValue, sharesPerPost: StatsValue, enabledNotifications: StatsPercentValue, growthGraph: StatsGraph, followersGraph: StatsGraph, muteGraph: StatsGraph, topHoursGraph: StatsGraph, interactionsGraph: StatsGraph, instantPageInteractionsGraph: StatsGraph, viewsBySourceGraph: StatsGraph, newFollowersBySourceGraph: StatsGraph, languagesGraph: StatsGraph, messageInteractions: [ChannelStatsMessageInteractions]) { init(
period: StatsDateRange,
followers: StatsValue,
viewsPerPost: StatsValue,
sharesPerPost: StatsValue,
enabledNotifications: StatsPercentValue,
growthGraph: StatsGraph,
followersGraph: StatsGraph,
muteGraph: StatsGraph,
topHoursGraph: StatsGraph,
interactionsGraph: StatsGraph,
instantPageInteractionsGraph: StatsGraph,
viewsBySourceGraph: StatsGraph,
newFollowersBySourceGraph: StatsGraph,
languagesGraph: StatsGraph,
reactionsByEmotionGraph: StatsGraph,
storyInteractionsGraph: StatsGraph,
storyReactionsByEmotionGraph: StatsGraph,
messageInteractions: [ChannelStatsMessageInteractions]
) {
self.period = period self.period = period
self.followers = followers self.followers = followers
self.viewsPerPost = viewsPerPost self.viewsPerPost = viewsPerPost
@ -86,6 +108,9 @@ public final class ChannelStats: Equatable {
self.viewsBySourceGraph = viewsBySourceGraph self.viewsBySourceGraph = viewsBySourceGraph
self.newFollowersBySourceGraph = newFollowersBySourceGraph self.newFollowersBySourceGraph = newFollowersBySourceGraph
self.languagesGraph = languagesGraph self.languagesGraph = languagesGraph
self.reactionsByEmotionGraph = reactionsByEmotionGraph
self.storyInteractionsGraph = storyInteractionsGraph
self.storyReactionsByEmotionGraph = storyReactionsByEmotionGraph
self.messageInteractions = messageInteractions self.messageInteractions = messageInteractions
} }
@ -132,6 +157,15 @@ public final class ChannelStats: Equatable {
if lhs.languagesGraph != rhs.languagesGraph { if lhs.languagesGraph != rhs.languagesGraph {
return false return false
} }
if lhs.reactionsByEmotionGraph != rhs.reactionsByEmotionGraph {
return false
}
if lhs.storyInteractionsGraph != rhs.storyInteractionsGraph {
return false
}
if lhs.storyReactionsByEmotionGraph != rhs.storyReactionsByEmotionGraph {
return false
}
if lhs.messageInteractions != rhs.messageInteractions { if lhs.messageInteractions != rhs.messageInteractions {
return false return false
} }
@ -139,39 +173,49 @@ public final class ChannelStats: Equatable {
} }
public func withUpdatedGrowthGraph(_ growthGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedFollowersGraph(_ followersGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedMuteGraph(_ muteGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedTopHoursGraph(_ viewsByHourGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedInstantPageInteractionsGraph(_ instantPageInteractionsGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedViewsBySourceGraph(_ viewsBySourceGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedNewFollowersBySourceGraph(_ newFollowersBySourceGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
} }
public func withUpdatedLanguagesGraph(_ languagesGraph: StatsGraph) -> ChannelStats { 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, messageInteractions: self.messageInteractions) 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)
}
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)
}
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)
}
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)
} }
} }
@ -424,6 +468,51 @@ private final class ChannelStatsContextImpl {
} }
} }
func loadReactionsByEmotionGraph() {
guard let stats = self._state.stats else {
return
}
if case let .OnDemand(token) = stats.reactionsByEmotionGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, 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))
strongSelf._statePromise.set(.single(strongSelf._state))
}
}), forKey: token)
}
}
func loadStoryInteractionsGraph() {
guard let stats = self._state.stats else {
return
}
if case let .OnDemand(token) = stats.storyInteractionsGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, 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))
strongSelf._statePromise.set(.single(strongSelf._state))
}
}), forKey: token)
}
}
func loadStoryReactionsByEmotionGraph() {
guard let stats = self._state.stats else {
return
}
if case let .OnDemand(token) = stats.storyReactionsByEmotionGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, 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))
strongSelf._statePromise.set(.single(strongSelf._state))
}
}), forKey: token)
}
}
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> { func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
if let token = graph.token { if let token = graph.token {
return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x) return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x)
@ -507,6 +596,21 @@ public final class ChannelStatsContext {
impl.loadLanguagesGraph() impl.loadLanguagesGraph()
} }
} }
public func loadReactionsByEmotionGraph() {
self.impl.with { impl in
impl.loadReactionsByEmotionGraph()
}
}
public func loadStoryInteractionsGraph() {
self.impl.with { impl in
impl.loadStoryInteractionsGraph()
}
}
public func loadStoryReactionsByEmotionGraph() {
self.impl.with { impl in
impl.loadStoryReactionsByEmotionGraph()
}
}
public func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> { public func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
return Signal { subscriber in return Signal { subscriber in
@ -1047,11 +1151,29 @@ extension ChannelStatsMessageInteractions {
extension ChannelStats { extension ChannelStats {
convenience init(apiBroadcastStats: Api.stats.BroadcastStats, peerId: PeerId) { convenience init(apiBroadcastStats: Api.stats.BroadcastStats, peerId: PeerId) {
switch apiBroadcastStats { switch apiBroadcastStats {
case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, apiGrowthGraph, apiFollowersGraph, apiMuteGraph, apiTopHoursGraph, apiInteractionsGraph, apiInstantViewInteractionsGraph, apiViewsBySourceGraph, apiNewFollowersBySourceGraph, apiLanguagesGraph, recentMessageInteractions): 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 growthGraph = StatsGraph(apiStatsGraph: apiGrowthGraph)
let isEmpty = growthGraph.isEmpty 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), messageInteractions: recentMessageInteractions.map { ChannelStatsMessageInteractions(apiMessageInteractionCounters: $0, peerId: peerId) }) 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) })
} }
} }
} }

View File

@ -0,0 +1,222 @@
import Foundation
import SwiftSignalKit
import Postbox
import TelegramApi
import MtProtoKit
public struct StoryStats: Equatable {
public let views: Int
public let forwards: Int
public let interactionsGraph: StatsGraph
public let interactionsGraphDelta: Int64
public let reactionsGraph: StatsGraph
init(views: Int, forwards: Int, interactionsGraph: StatsGraph, interactionsGraphDelta: Int64, reactionsGraph: StatsGraph) {
self.views = views
self.forwards = forwards
self.interactionsGraph = interactionsGraph
self.interactionsGraphDelta = interactionsGraphDelta
self.reactionsGraph = reactionsGraph
}
public static func == (lhs: StoryStats, rhs: StoryStats) -> Bool {
if lhs.views != rhs.views {
return false
}
if lhs.forwards != rhs.forwards {
return false
}
if lhs.interactionsGraph != rhs.interactionsGraph {
return false
}
if lhs.interactionsGraphDelta != rhs.interactionsGraphDelta {
return false
}
if lhs.reactionsGraph != rhs.reactionsGraph {
return false
}
return true
}
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> StoryStats {
return StoryStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: self.interactionsGraphDelta, reactionsGraph: self.reactionsGraph)
}
}
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
} else {
return nil
}
} |> mapToSignal { peer -> Signal<StoryStats?, NoError> in
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
return .never()
}
var flags: Int32 = 0
if dark {
flags |= (1 << 1)
}
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)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(request)
}
} else {
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
// }
// }
return signal
|> mapToSignal { result -> Signal<StoryStats?, MTRpcError> in
if case let .storyStats(apiInteractionsGraph, apiReactionsGraph) = result {
let interactionsGraph = StatsGraph(apiStatsGraph: apiInteractionsGraph)
var interactionsGraphDelta: Int64 = 86400
if case let .Loaded(_, data) = interactionsGraph {
if let start = data.range(of: "[\"x\",") {
let substring = data.suffix(from: start.upperBound)
if let end = substring.range(of: "],") {
let valuesString = substring.prefix(through: substring.index(before: end.lowerBound))
let values = valuesString.components(separatedBy: ",").compactMap { Int64($0) }
if values.count > 1 {
let first = values[0]
let second = values[1]
let delta = abs(second - first) / 1000
interactionsGraphDelta = delta
}
}
}
}
let reactionsGraph = StatsGraph(apiStatsGraph: apiReactionsGraph)
return .single(StoryStats(
views: views,
forwards: forwards,
interactionsGraph: interactionsGraph,
interactionsGraphDelta: interactionsGraphDelta,
reactionsGraph: reactionsGraph
))
} else {
return .single(nil)
}
}
|> retryRequest
}
}
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
private var _state: StoryStatsContextState {
didSet {
if self._state != oldValue {
self._statePromise.set(.single(self._state))
}
}
}
private let _statePromise = Promise<StoryStatsContextState>()
var state: Signal<StoryStatsContextState, NoError> {
return self._statePromise.get()
}
private let disposable = MetaDisposable()
private let disposables = DisposableDict<String>()
init(postbox: Postbox, network: Network, datacenterId: Int32, 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)
self._statePromise.set(.single(self._state))
self.load()
}
deinit {
assert(Queue.mainQueue().isCurrent())
self.disposable.dispose()
self.disposables.dispose()
}
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)
|> deliverOnMainQueue).start(next: { [weak self] stats in
if let strongSelf = self {
strongSelf._state = StoryStatsContextState(stats: stats)
strongSelf._statePromise.set(.single(strongSelf._state))
}
}))
}
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)
} else {
return .single(nil)
}
}
}
public final class StoryStatsContext {
private let impl: QueueLocalObject<StoryStatsContextImpl>
public var state: Signal<StoryStatsContextState, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.state.start(next: { value in
subscriber.putNext(value)
}))
}
return disposable
}
}
public init(postbox: Postbox, network: Network, datacenterId: Int32, peerId: EnginePeer.Id, storyId: Int32) {
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
return StoryStatsContextImpl(postbox: postbox, network: network, datacenterId: datacenterId, peerId: peerId, storyId: storyId)
})
}
public func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.loadDetailedGraph(graph, x: x).start(next: { value in
subscriber.putNext(value)
subscriber.putCompletion()
}))
}
return disposable
}
}
}

View File

@ -984,7 +984,9 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
entities: apiEntities, entities: apiEntities,
privacyRules: privacyRules, privacyRules: privacyRules,
randomId: randomId, randomId: randomId,
period: Int32(period) period: Int32(period),
fwdFromId: nil,
fwdFromStory: nil
)) ))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in |> `catch` { _ -> Signal<Api.Updates?, NoError> in
@ -1008,7 +1010,7 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
for update in updates.allUpdates { for update in updates.allUpdates {
if case let .updateStory(_, story) = update { if case let .updateStory(_, story) = update {
switch story { switch story {
case let .storyItem(_, idValue, _, _, _, _, media, _, _, _, _): case let .storyItem(_, idValue, _, _, _, _, _, media, _, _, _, _):
if let parsedStory = Stories.StoredItem(apiStoryItem: story, peerId: toPeerId, transaction: transaction) { if let parsedStory = Stories.StoredItem(apiStoryItem: story, peerId: toPeerId, transaction: transaction) {
var items = transaction.getStoryItems(peerId: toPeerId) var items = transaction.getStoryItems(peerId: toPeerId)
var updatedItems: [Stories.Item] = [] var updatedItems: [Stories.Item] = []
@ -1169,7 +1171,7 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
for update in updates.allUpdates { for update in updates.allUpdates {
if case let .updateStory(_, story) = update { if case let .updateStory(_, story) = update {
switch story { switch story {
case let .storyItem(_, _, _, _, _, _, media, _, _, _, _): case let .storyItem(_, _, _, _, _, _, _, media, _, _, _, _):
let (parsedMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId) let (parsedMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId)
if let parsedMedia = parsedMedia, let originalMedia = originalMedia { if let parsedMedia = parsedMedia, let originalMedia = originalMedia {
applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false) applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false)
@ -1493,7 +1495,7 @@ func _internal_updateStoriesArePinned(account: Account, peerId: PeerId, ids: [In
extension Api.StoryItem { extension Api.StoryItem {
var id: Int32 { var id: Int32 {
switch self { switch self {
case let .storyItem(_, id, _, _, _, _, _, _, _, _, _): case let .storyItem(_, id, _, _, _, _, _, _, _, _, _, _):
return id return id
case let .storyItemDeleted(id): case let .storyItemDeleted(id):
return id return id
@ -1539,7 +1541,8 @@ extension Stories.Item.Views {
extension Stories.StoredItem { extension Stories.StoredItem {
init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) { init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) {
switch apiStoryItem { switch apiStoryItem {
case let .storyItem(flags, id, date, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction): case let .storyItem(flags, id, date, fwdFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction):
let _ = fwdFrom
let (parsedMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId) let (parsedMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
if let parsedMedia = parsedMedia { if let parsedMedia = parsedMedia {
var parsedPrivacy: Stories.Item.Privacy? var parsedPrivacy: Stories.Item.Privacy?

View File

@ -184,12 +184,29 @@ func _internal_revertChatWallpaper(account: Account, peerId: EnginePeer.Id) -> S
} }
let flags: Int32 = 1 << 4 let flags: Int32 = 1 << 4
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: nil, settings: nil, id: nil), automaticFloodWait: false) return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: nil, settings: nil, id: nil), automaticFloodWait: false)
|> `catch` { _ -> Signal<Api.Updates, RevertChatWallpaperError> in |> map(Optional.init)
|> `catch` { error -> Signal<Api.Updates?, RevertChatWallpaperError> in
if error.description == "WALLPAPER_NOT_FOUND" {
return .single(nil)
}
return .fail(.generic) return .fail(.generic)
} }
|> mapToSignal { updates -> Signal<Void, RevertChatWallpaperError> in |> mapToSignal { updates -> Signal<Void, RevertChatWallpaperError> in
account.stateManager.addUpdates(updates) if let updates = updates {
return .complete() account.stateManager.addUpdates(updates)
return .complete()
} else {
return account.postbox.transaction { transaction in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
return current.withUpdatedWallpaper(nil)
} else {
return current
}
})
}
|> castError(RevertChatWallpaperError.self)
}
} }
} }
} }

View File

@ -684,7 +684,7 @@ private final class PeerButtonsStackNode: ASDisplayNode {
var titleColor = titleColor var titleColor = titleColor
var backgroundColor = backgroundColor var backgroundColor = backgroundColor
if incoming, let nameColor = peer.nameColor { if incoming, let nameColor = peer.nameColor, makeChannelButtonLayouts.count > 1 {
titleColor = context.peerNameColors.get(nameColor, dark: dark).main titleColor = context.peerNameColors.get(nameColor, dark: dark).main
backgroundColor = titleColor.withAlphaComponent(0.1) backgroundColor = titleColor.withAlphaComponent(0.1)
} }