mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Statistics improvements
This commit is contained in:
parent
1fced74098
commit
13baadc3e7
@ -10498,7 +10498,13 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Stats.MessageReactionsTitle" = "REACTIONS";
|
"Stats.MessageReactionsTitle" = "REACTIONS";
|
||||||
|
|
||||||
|
"MediaEditor.RemoveVideo" = "Remove Video";
|
||||||
|
|
||||||
"Conversation.LaunchApp" = "LAUNCH APP";
|
"Conversation.LaunchApp" = "LAUNCH APP";
|
||||||
|
|
||||||
"Message.AdSponsoredLabel" = "Sponsored";
|
"Message.AdSponsoredLabel" = "Sponsored";
|
||||||
"Message.AdRecommendedLabel" = "Recommended";
|
"Message.AdRecommendedLabel" = "Recommended";
|
||||||
|
|
||||||
|
"Stats.StoryTitle" = "Story Statistics";
|
||||||
|
|
||||||
|
"Channel.Info.Settings" = "Channel Settings";
|
||||||
|
@ -211,9 +211,9 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
|||||||
if peer.unreadCount > 0 {
|
if peer.unreadCount > 0 {
|
||||||
badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active)
|
badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ContactsPeerItem(
|
return ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: nameSortOrder,
|
sortOrder: nameSortOrder,
|
||||||
displayOrder: nameDisplayOrder,
|
displayOrder: nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -355,7 +355,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
context: context,
|
context: context,
|
||||||
title: title,
|
title: title,
|
||||||
image: image,
|
image: image,
|
||||||
@ -569,7 +569,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -608,7 +608,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
let status: ContactsPeerItemStatus = .none
|
let status: ContactsPeerItemStatus = .none
|
||||||
|
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -670,7 +670,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
||||||
|
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -889,7 +889,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -928,7 +928,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
let status: ContactsPeerItemStatus = .none
|
let status: ContactsPeerItemStatus = .none
|
||||||
|
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -990,7 +990,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
||||||
|
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
sortOrder: presentationData.nameSortOrder,
|
sortOrder: presentationData.nameSortOrder,
|
||||||
displayOrder: presentationData.nameDisplayOrder,
|
displayOrder: presentationData.nameDisplayOrder,
|
||||||
context: context,
|
context: context,
|
||||||
@ -1057,7 +1057,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||||
context: context,
|
context: context,
|
||||||
title: title,
|
title: title,
|
||||||
image: image,
|
image: image,
|
||||||
|
@ -161,12 +161,14 @@ public final class ItemListPresentationData: Equatable {
|
|||||||
public let fontSize: PresentationFontSize
|
public let fontSize: PresentationFontSize
|
||||||
public let strings: PresentationStrings
|
public let strings: PresentationStrings
|
||||||
public let nameDisplayOrder: PresentationPersonNameOrder
|
public let nameDisplayOrder: PresentationPersonNameOrder
|
||||||
|
public let dateTimeFormat: PresentationDateTimeFormat
|
||||||
|
|
||||||
public init(theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) {
|
public init(theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.fontSize = fontSize
|
self.fontSize = fontSize
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
|
self.dateTimeFormat = dateTimeFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: ItemListPresentationData, rhs: ItemListPresentationData) -> Bool {
|
public static func ==(lhs: ItemListPresentationData, rhs: ItemListPresentationData) -> Bool {
|
||||||
@ -182,6 +184,9 @@ public final class ItemListPresentationData: Equatable {
|
|||||||
if lhs.nameDisplayOrder != rhs.nameDisplayOrder {
|
if lhs.nameDisplayOrder != rhs.nameDisplayOrder {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.dateTimeFormat != rhs.dateTimeFormat {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,6 +237,6 @@ public extension PresentationFontSize {
|
|||||||
|
|
||||||
public extension ItemListPresentationData {
|
public extension ItemListPresentationData {
|
||||||
convenience init(_ presentationData: PresentationData) {
|
convenience init(_ presentationData: PresentationData) {
|
||||||
self.init(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder)
|
self.init(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ swift_library(
|
|||||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
"//submodules/Display:Display",
|
"//submodules/Display:Display",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
"//submodules/Postbox:Postbox",
|
"//submodules/Postbox:Postbox",
|
||||||
"//submodules/TelegramCore:TelegramCore",
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||||
@ -35,6 +36,7 @@ swift_library(
|
|||||||
"//submodules/PremiumUI:PremiumUI",
|
"//submodules/PremiumUI:PremiumUI",
|
||||||
"//submodules/InviteLinksUI:InviteLinksUI",
|
"//submodules/InviteLinksUI:InviteLinksUI",
|
||||||
"//submodules/ShareController:ShareController",
|
"//submodules/ShareController:ShareController",
|
||||||
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -27,7 +27,7 @@ private let initialBoostersDisplayedLimit: Int32 = 5
|
|||||||
private final class ChannelStatsControllerArguments {
|
private final class ChannelStatsControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let loadDetailedGraph: (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>
|
let loadDetailedGraph: (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>
|
||||||
let openMessageStats: (MessageId) -> Void
|
let openPostStats: (EnginePeer, StatsPostItem) -> Void
|
||||||
let contextAction: (MessageId, ASDisplayNode, ContextGesture?) -> Void
|
let contextAction: (MessageId, ASDisplayNode, ContextGesture?) -> Void
|
||||||
let copyBoostLink: (String) -> Void
|
let copyBoostLink: (String) -> Void
|
||||||
let shareBoostLink: (String) -> Void
|
let shareBoostLink: (String) -> Void
|
||||||
@ -37,10 +37,10 @@ private final class ChannelStatsControllerArguments {
|
|||||||
let createPrepaidGiveaway: (PrepaidGiveaway) -> Void
|
let createPrepaidGiveaway: (PrepaidGiveaway) -> Void
|
||||||
let updateGiftsSelected: (Bool) -> Void
|
let updateGiftsSelected: (Bool) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openMessage: @escaping (MessageId) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void) {
|
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openPostStats: @escaping (EnginePeer, StatsPostItem) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.loadDetailedGraph = loadDetailedGraph
|
self.loadDetailedGraph = loadDetailedGraph
|
||||||
self.openMessageStats = openMessage
|
self.openPostStats = openPostStats
|
||||||
self.contextAction = contextAction
|
self.contextAction = contextAction
|
||||||
self.copyBoostLink = copyBoostLink
|
self.copyBoostLink = copyBoostLink
|
||||||
self.shareBoostLink = shareBoostLink
|
self.shareBoostLink = shareBoostLink
|
||||||
@ -75,6 +75,45 @@ private enum StatsSection: Int32 {
|
|||||||
case gifts
|
case gifts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum StatsPostItem: Equatable {
|
||||||
|
static func == (lhs: StatsPostItem, rhs: StatsPostItem) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .message(lhsMessage):
|
||||||
|
if case let .message(rhsMessage) = rhs {
|
||||||
|
return lhsMessage.id == rhsMessage.id
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .story(lhsStory):
|
||||||
|
if case let .story(rhsStory) = rhs, lhsStory == rhsStory {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case message(Message)
|
||||||
|
case story(EngineStoryItem)
|
||||||
|
|
||||||
|
var isStory: Bool {
|
||||||
|
if case .story = self {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var timestamp: Int32 {
|
||||||
|
switch self {
|
||||||
|
case let .message(message):
|
||||||
|
return message.timestamp
|
||||||
|
case let .story(story):
|
||||||
|
return story.timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum StatsEntry: ItemListNodeEntry {
|
private enum StatsEntry: ItemListNodeEntry {
|
||||||
case overviewTitle(PresentationTheme, String, String)
|
case overviewTitle(PresentationTheme, String, String)
|
||||||
case overview(PresentationTheme, ChannelStats)
|
case overview(PresentationTheme, ChannelStats)
|
||||||
@ -116,7 +155,7 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
case instantPageInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
|
case instantPageInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
|
||||||
|
|
||||||
case postsTitle(PresentationTheme, String)
|
case postsTitle(PresentationTheme, String)
|
||||||
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Message, ChannelStatsMessageInteractions)
|
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, StatsPostItem, ChannelStatsMessageInteractions)
|
||||||
|
|
||||||
case boostLevel(PresentationTheme, Int32, Int32, CGFloat)
|
case boostLevel(PresentationTheme, Int32, Int32, CGFloat)
|
||||||
|
|
||||||
@ -242,7 +281,7 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return 25
|
return 25
|
||||||
case .postsTitle:
|
case .postsTitle:
|
||||||
return 26
|
return 26
|
||||||
case let .post(index, _, _, _, _, _):
|
case let .post(index, _, _, _, _, _, _):
|
||||||
return 27 + index
|
return 27 + index
|
||||||
case .boostLevel:
|
case .boostLevel:
|
||||||
return 2000
|
return 2000
|
||||||
@ -445,8 +484,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .post(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsMessage, lhsInteractions):
|
case let .post(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsPost, 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 {
|
if case let .post(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsPost, rhsInteractions) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, arePeersEqual(lhsPeer, rhsPeer), lhsPost == rhsPost, lhsInteractions == rhsInteractions {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -610,12 +649,14 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, sectionId: self.section, style: .blocks)
|
}, sectionId: self.section, style: .blocks)
|
||||||
case let .post(_, _, _, _, message, interactions):
|
case let .post(_, _, _, _, peer, post, interactions):
|
||||||
return StatsMessageItem(context: arguments.context, presentationData: presentationData, message: message, views: interactions.views, forwards: interactions.forwards, sectionId: self.section, style: .blocks, action: {
|
return StatsMessageItem(context: arguments.context, presentationData: presentationData, peer: peer, item: post, views: interactions.views, reactions: interactions.reactions, forwards: interactions.forwards, sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.openMessageStats(message.id)
|
arguments.openPostStats(EnginePeer(peer), post)
|
||||||
}, contextAction: { node, gesture in
|
}, contextAction: !post.isStory ? { node, gesture in
|
||||||
arguments.contextAction(message.id, node, gesture)
|
if case let .message(message) = post {
|
||||||
})
|
arguments.contextAction(message.id, node, gesture)
|
||||||
|
}
|
||||||
|
} : nil)
|
||||||
case let .boosterTabs(_, boostText, giftText, giftSelected):
|
case let .boosterTabs(_, boostText, giftText, giftSelected):
|
||||||
return BoostsTabsItem(theme: presentationData.theme, boostsText: boostText, giftsText: giftText, selectedTab: giftSelected ? .gifts : .boosts, sectionId: self.section, selectionUpdated: { tab in
|
return BoostsTabsItem(theme: presentationData.theme, boostsText: boostText, giftsText: giftText, selectedTab: giftSelected ? .gifts : .boosts, sectionId: self.section, selectionUpdated: { tab in
|
||||||
arguments.updateGiftsSelected(tab == .gifts)
|
arguments.updateGiftsSelected(tab == .gifts)
|
||||||
@ -775,7 +816,7 @@ private struct ChannelStatsControllerState: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, interactions: [MessageId: ChannelStatsMessageInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData, giveawayAvailable: Bool) -> [StatsEntry] {
|
private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, stories: PeerStoryListContext.State?, interactions: [MessageId: ChannelStatsMessageInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData, giveawayAvailable: Bool) -> [StatsEntry] {
|
||||||
var entries: [StatsEntry] = []
|
var entries: [StatsEntry] = []
|
||||||
|
|
||||||
switch state.section {
|
switch state.section {
|
||||||
@ -847,14 +888,35 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
|
|||||||
entries.append(.storyReactionsByEmotionGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.storyReactionsByEmotionGraph, .bars))
|
entries.append(.storyReactionsByEmotionGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.storyReactionsByEmotionGraph, .bars))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let messages = messages, !messages.isEmpty, let interactions = interactions, !interactions.isEmpty {
|
|
||||||
|
var posts: [StatsPostItem] = []
|
||||||
|
if let messages, let interactions {
|
||||||
|
for message in messages {
|
||||||
|
if let _ = interactions[message.id] {
|
||||||
|
posts.append(.message(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let stories {
|
||||||
|
for story in stories.items {
|
||||||
|
posts.append(.story(story))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
posts.sort(by: { $0.timestamp > $1.timestamp })
|
||||||
|
|
||||||
|
if !posts.isEmpty, let interactions, let peer = peer?._asPeer() {
|
||||||
entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle))
|
entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle))
|
||||||
var index: Int32 = 0
|
var index: Int32 = 0
|
||||||
for message in messages {
|
for post in posts {
|
||||||
if let interactions = interactions[message.id] {
|
switch post {
|
||||||
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, message, interactions))
|
case let .message(message):
|
||||||
index += 1
|
if let interactions = interactions[message.id] {
|
||||||
|
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, post, interactions))
|
||||||
|
}
|
||||||
|
case let .story(story):
|
||||||
|
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, post, ChannelStatsMessageInteractions(messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), views: Int32(story.views?.seenCount ?? 0), forwards: Int32(story.views?.forwardCount ?? 0), reactions: Int32(story.views?.reactedCount ?? 0))))
|
||||||
}
|
}
|
||||||
|
index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -979,13 +1041,15 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
|
|
||||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||||
|
|
||||||
var openMessageStatsImpl: ((MessageId) -> Void)?
|
var openPostStatsImpl: ((EnginePeer, StatsPostItem) -> Void)?
|
||||||
var contextActionImpl: ((MessageId, ASDisplayNode, ContextGesture?) -> Void)?
|
var contextActionImpl: ((MessageId, ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
let dataPromise = Promise<ChannelStats?>(nil)
|
let dataPromise = Promise<ChannelStats?>(nil)
|
||||||
let messagesPromise = Promise<MessageHistoryView?>(nil)
|
let messagesPromise = Promise<MessageHistoryView?>(nil)
|
||||||
|
|
||||||
|
let storiesPromise = Promise<PeerStoryListContext.State?>()
|
||||||
|
|
||||||
let datacenterId: Int32 = statsDatacenterId ?? 0
|
let datacenterId: Int32 = statsDatacenterId ?? 0
|
||||||
|
|
||||||
let statsContext = ChannelStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, peerId: peerId)
|
let statsContext = ChannelStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, peerId: peerId)
|
||||||
@ -1027,8 +1091,8 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
|
|
||||||
let arguments = ChannelStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in
|
let arguments = ChannelStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in
|
||||||
return statsContext.loadDetailedGraph(graph, x: x)
|
return statsContext.loadDetailedGraph(graph, x: x)
|
||||||
}, openMessage: { messageId in
|
}, openPostStats: { peer, item in
|
||||||
openMessageStatsImpl?(messageId)
|
openPostStatsImpl?(peer, item)
|
||||||
}, contextAction: { messageId, node, gesture in
|
}, contextAction: { messageId, node, gesture in
|
||||||
contextActionImpl?(messageId, node, gesture)
|
contextActionImpl?(messageId, node, gesture)
|
||||||
}, copyBoostLink: { link in
|
}, copyBoostLink: { link in
|
||||||
@ -1138,6 +1202,16 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
}
|
}
|
||||||
messagesPromise.set(.single(nil) |> then(messageView))
|
messagesPromise.set(.single(nil) |> then(messageView))
|
||||||
|
|
||||||
|
let storyList = PeerStoryListContext(account: context.account, peerId: peerId, isArchived: false)
|
||||||
|
storyList.loadMore()
|
||||||
|
storiesPromise.set(
|
||||||
|
.single(nil)
|
||||||
|
|> then(
|
||||||
|
storyList.state
|
||||||
|
|> map(Optional.init)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
||||||
|
|
||||||
let previousData = Atomic<ChannelStats?>(value: nil)
|
let previousData = Atomic<ChannelStats?>(value: nil)
|
||||||
@ -1149,13 +1223,14 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
||||||
dataPromise.get(),
|
dataPromise.get(),
|
||||||
messagesPromise.get(),
|
messagesPromise.get(),
|
||||||
|
storiesPromise.get(),
|
||||||
boostData,
|
boostData,
|
||||||
boostsContext.state,
|
boostsContext.state,
|
||||||
giftsContext.state,
|
giftsContext.state,
|
||||||
longLoadingSignal
|
longLoadingSignal
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, state, peer, data, messageView, boostData, boostersState, giftsState, longLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state, peer, data, messageView, stories, boostData, boostersState, giftsState, longLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
let previous = previousData.swap(data)
|
let previous = previousData.swap(data)
|
||||||
var emptyStateItem: ItemListControllerEmptyStateItem?
|
var emptyStateItem: ItemListControllerEmptyStateItem?
|
||||||
switch state.section {
|
switch state.section {
|
||||||
@ -1183,13 +1258,14 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .sectionControl([presentationData.strings.Stats_Statistics, presentationData.strings.Stats_Boosts], state.section == .boosts ? 1 : 0), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .sectionControl([presentationData.strings.Stats_Statistics, presentationData.strings.Stats_Boosts], state.section == .boosts ? 1 : 0), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(state: state, peer: peer, data: data, messages: messages, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, presentationData: presentationData, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(state: state, peer: peer, data: data, messages: messages, stories: stories, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, presentationData: presentationData, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|> afterDisposed {
|
|> afterDisposed {
|
||||||
actionsDisposable.dispose()
|
actionsDisposable.dispose()
|
||||||
let _ = statsContext.state
|
let _ = statsContext.state
|
||||||
|
let _ = storyList.state
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
@ -1206,8 +1282,15 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
controller.didDisappear = { [weak controller] _ in
|
controller.didDisappear = { [weak controller] _ in
|
||||||
controller?.clearItemNodesHighlight(animated: true)
|
controller?.clearItemNodesHighlight(animated: true)
|
||||||
}
|
}
|
||||||
openMessageStatsImpl = { [weak controller] messageId in
|
openPostStatsImpl = { [weak controller] peer, post in
|
||||||
controller?.push(messageStatsController(context: context, messageId: messageId, statsDatacenterId: statsDatacenterId))
|
let subject: StatsSubject
|
||||||
|
switch post {
|
||||||
|
case let .message(message):
|
||||||
|
subject = .message(id: message.id)
|
||||||
|
case let .story(story):
|
||||||
|
subject = .story(peer: peer, storyItem: story)
|
||||||
|
}
|
||||||
|
controller?.push(messageStatsController(context: context, subject: subject, statsDatacenterId: statsDatacenterId))
|
||||||
}
|
}
|
||||||
contextActionImpl = { [weak controller] messageId, sourceNode, gesture in
|
contextActionImpl = { [weak controller] messageId, sourceNode, gesture in
|
||||||
guard let controller = controller, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
|
guard let controller = controller, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import AsyncDisplayKit
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
@ -35,7 +36,7 @@ private enum StatsSection: Int32 {
|
|||||||
|
|
||||||
private enum StatsEntry: ItemListNodeEntry {
|
private enum StatsEntry: ItemListNodeEntry {
|
||||||
case overviewTitle(PresentationTheme, String)
|
case overviewTitle(PresentationTheme, String)
|
||||||
case overview(PresentationTheme, MessageStats, Int32?)
|
case overview(PresentationTheme, PostStats, Int32?)
|
||||||
|
|
||||||
case interactionsTitle(PresentationTheme, String)
|
case interactionsTitle(PresentationTheme, String)
|
||||||
case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
|
case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
|
||||||
@ -89,8 +90,14 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .overview(lhsTheme, lhsStats, lhsPublicShares):
|
case let .overview(lhsTheme, lhsStats, lhsPublicShares):
|
||||||
if case let .overview(rhsTheme, rhsStats, rhsPublicShares) = rhs, lhsTheme === rhsTheme, lhsStats == rhsStats, lhsPublicShares == rhsPublicShares {
|
if case let .overview(rhsTheme, rhsStats, rhsPublicShares) = rhs, lhsTheme === rhsTheme, lhsPublicShares == rhsPublicShares {
|
||||||
return true
|
if let lhsMessageStats = lhsStats as? MessageStats, let rhsMessageStats = rhsStats as? MessageStats {
|
||||||
|
return lhsMessageStats == rhsMessageStats
|
||||||
|
} else if let lhsStoryStats = lhsStats as? StoryStats, let rhsStoryStats = rhsStats as? StoryStats {
|
||||||
|
return lhsStoryStats == rhsStoryStats
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -172,7 +179,7 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func messageStatsControllerEntries(data: MessageStats?, messages: SearchMessagesResult?, presentationData: PresentationData) -> [StatsEntry] {
|
private func messageStatsControllerEntries(data: PostStats?, messages: SearchMessagesResult?, presentationData: PresentationData) -> [StatsEntry] {
|
||||||
var entries: [StatsEntry] = []
|
var entries: [StatsEntry] = []
|
||||||
|
|
||||||
if let data = data {
|
if let data = data {
|
||||||
@ -212,44 +219,98 @@ private func messageStatsControllerEntries(data: MessageStats?, messages: Search
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
public func messageStatsController(context: AccountContext, messageId: EngineMessage.Id, statsDatacenterId: Int32?) -> ViewController {
|
public enum StatsSubject {
|
||||||
|
case message(id: EngineMessage.Id)
|
||||||
|
case story(peer: EnginePeer, storyItem: EngineStoryItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol PostStats {
|
||||||
|
var views: Int { get }
|
||||||
|
var forwards: Int { get }
|
||||||
|
var interactionsGraph: StatsGraph { get }
|
||||||
|
var interactionsGraphDelta: Int64 { get }
|
||||||
|
var reactionsGraph: StatsGraph { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MessageStats: PostStats {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StoryStats: PostStats {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public func messageStatsController(context: AccountContext, subject: StatsSubject, statsDatacenterId: Int32?) -> ViewController {
|
||||||
var navigateToMessageImpl: ((EngineMessage.Id) -> Void)?
|
var navigateToMessageImpl: ((EngineMessage.Id) -> Void)?
|
||||||
|
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
let dataPromise = Promise<MessageStats?>(nil)
|
let dataPromise = Promise<PostStats?>(nil)
|
||||||
let messagesPromise = Promise<(SearchMessagesResult, SearchMessagesState)?>(nil)
|
let messagesPromise = Promise<(SearchMessagesResult, SearchMessagesState)?>(nil)
|
||||||
|
|
||||||
let datacenterId: Int32 = statsDatacenterId ?? 0
|
let datacenterId: Int32 = statsDatacenterId ?? 0
|
||||||
|
|
||||||
let statsContext = MessageStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, messageId: messageId)
|
let anyStatsContext: Any
|
||||||
let dataSignal: Signal<MessageStats?, NoError> = statsContext.state
|
let dataSignal: Signal<PostStats?, NoError>
|
||||||
|> map { state in
|
var loadDetailedGraphImpl: ((StatsGraph, Int64) -> Signal<StatsGraph?, NoError>)?
|
||||||
return state.stats
|
switch subject {
|
||||||
|
case let .message(id):
|
||||||
|
let statsContext = MessageStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, messageId: id)
|
||||||
|
loadDetailedGraphImpl = { [weak statsContext] graph, x in
|
||||||
|
return statsContext?.loadDetailedGraph(graph, x: x) ?? .single(nil)
|
||||||
|
}
|
||||||
|
dataSignal = statsContext.state
|
||||||
|
|> map { state in
|
||||||
|
return state.stats
|
||||||
|
}
|
||||||
|
dataPromise.set(.single(nil) |> then(dataSignal))
|
||||||
|
anyStatsContext = statsContext
|
||||||
|
case let .story(peer, storyItem):
|
||||||
|
let statsContext = StoryStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, peerId: peer.id, storyId: storyItem.id)
|
||||||
|
loadDetailedGraphImpl = { [weak statsContext] graph, x in
|
||||||
|
return statsContext?.loadDetailedGraph(graph, x: x) ?? .single(nil)
|
||||||
|
}
|
||||||
|
dataSignal = statsContext.state
|
||||||
|
|> map { state in
|
||||||
|
return state.stats
|
||||||
|
}
|
||||||
|
dataPromise.set(.single(nil) |> then(dataSignal))
|
||||||
|
anyStatsContext = statsContext
|
||||||
}
|
}
|
||||||
dataPromise.set(.single(nil) |> then(dataSignal))
|
|
||||||
|
|
||||||
let arguments = MessageStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in
|
let arguments = MessageStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in
|
||||||
return statsContext.loadDetailedGraph(graph, x: x)
|
return loadDetailedGraphImpl?(graph, x) ?? .single(nil)
|
||||||
}, openMessage: { messageId in
|
}, openMessage: { messageId in
|
||||||
navigateToMessageImpl?(messageId)
|
navigateToMessageImpl?(messageId)
|
||||||
})
|
})
|
||||||
|
|
||||||
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
||||||
|
|
||||||
let previousData = Atomic<MessageStats?>(value: nil)
|
let previousData = Atomic<PostStats?>(value: nil)
|
||||||
|
|
||||||
let searchSignal = context.engine.messages.searchMessages(location: .publicForwards(messageId: messageId, datacenterId: Int(datacenterId)), query: "", state: nil)
|
if case let .message(id) = subject {
|
||||||
|> map(Optional.init)
|
let searchSignal = context.engine.messages.searchMessages(location: .publicForwards(messageId: id, datacenterId: Int(datacenterId)), query: "", state: nil)
|
||||||
|> afterNext { result in
|
|> map(Optional.init)
|
||||||
if let result = result {
|
|> afterNext { result in
|
||||||
for message in result.0.messages {
|
if let result = result {
|
||||||
if let peer = message.peers[message.id.peerId], let peerReference = PeerReference(peer) {
|
for message in result.0.messages {
|
||||||
let _ = context.engine.peers.updatedRemotePeer(peer: peerReference).start()
|
if let peer = message.peers[message.id.peerId], let peerReference = PeerReference(peer) {
|
||||||
|
let _ = context.engine.peers.updatedRemotePeer(peer: peerReference).start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
messagesPromise.set(.single(nil) |> then(searchSignal))
|
||||||
|
} else {
|
||||||
|
messagesPromise.set(.single(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
let iconNode: ASDisplayNode?
|
||||||
|
if case let .story(peer, storyItem) = subject {
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
iconNode = StoryIconNode(context: context, theme: presentationData.theme, peer: peer._asPeer(), storyItem: storyItem)
|
||||||
|
} else {
|
||||||
|
iconNode = nil
|
||||||
}
|
}
|
||||||
messagesPromise.set(.single(nil) |> then(searchSignal))
|
|
||||||
|
|
||||||
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), messagesPromise.get(), longLoadingSignal)
|
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), messagesPromise.get(), longLoadingSignal)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
@ -264,14 +325,22 @@ public func messageStatsController(context: AccountContext, messageId: EngineMes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Stats_MessageTitle), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
let title: String
|
||||||
|
switch subject {
|
||||||
|
case .message:
|
||||||
|
title = presentationData.strings.Stats_MessageTitle
|
||||||
|
case .story:
|
||||||
|
title = presentationData.strings.Stats_StoryTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: iconNode.flatMap { ItemListNavigationButton(content: .node($0), style: .regular, enabled: true, action: { }) }, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: messageStatsControllerEntries(data: data, messages: search?.0, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: messageStatsControllerEntries(data: data, messages: search?.0, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|> afterDisposed {
|
|> afterDisposed {
|
||||||
actionsDisposable.dispose()
|
actionsDisposable.dispose()
|
||||||
let _ = statsContext.state
|
let _ = anyStatsContext
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
@ -282,6 +351,12 @@ public func messageStatsController(context: AccountContext, messageId: EngineMes
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// controller.visibleBottomContentOffsetChanged = { offset in
|
||||||
|
// let state = stateValue.with { $0 }
|
||||||
|
// if case let .known(value) = offset, value < 100.0, case .boosts = state.section, state.boostersExpanded {
|
||||||
|
// boostsContext.loadMore()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
controller.didDisappear = { [weak controller] _ in
|
controller.didDisappear = { [weak controller] _ in
|
||||||
controller?.clearItemNodesHighlight(animated: true)
|
controller?.clearItemNodesHighlight(animated: true)
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@ import PresentationDataUtils
|
|||||||
|
|
||||||
class MessageStatsOverviewItem: ListViewItem, ItemListItem {
|
class MessageStatsOverviewItem: ListViewItem, ItemListItem {
|
||||||
let presentationData: ItemListPresentationData
|
let presentationData: ItemListPresentationData
|
||||||
let stats: MessageStats
|
let stats: PostStats
|
||||||
let publicShares: Int32?
|
let publicShares: Int32?
|
||||||
let sectionId: ItemListSectionId
|
let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
|
|
||||||
init(presentationData: ItemListPresentationData, stats: MessageStats, publicShares: Int32?, sectionId: ItemListSectionId, style: ItemListStyle) {
|
init(presentationData: ItemListPresentationData, stats: PostStats, publicShares: Int32?, sectionId: ItemListSectionId, style: ItemListStyle) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.stats = stats
|
self.stats = stats
|
||||||
self.publicShares = publicShares
|
self.publicShares = publicShares
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
import ComponentFlow
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
@ -11,23 +12,28 @@ import TelegramStringFormatting
|
|||||||
import ItemListUI
|
import ItemListUI
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import PhotoResources
|
import PhotoResources
|
||||||
|
import AvatarStoryIndicatorComponent
|
||||||
|
|
||||||
public class StatsMessageItem: ListViewItem, ItemListItem {
|
public class StatsMessageItem: ListViewItem, ItemListItem {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let presentationData: ItemListPresentationData
|
let presentationData: ItemListPresentationData
|
||||||
let message: Message
|
let peer: Peer
|
||||||
|
let item: StatsPostItem
|
||||||
let views: Int32
|
let views: Int32
|
||||||
|
let reactions: Int32
|
||||||
let forwards: Int32
|
let forwards: Int32
|
||||||
public let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let action: (() -> Void)?
|
let action: (() -> Void)?
|
||||||
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: ItemListPresentationData, message: Message, views: Int32, forwards: Int32, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) {
|
init(context: AccountContext, presentationData: ItemListPresentationData, peer: Peer, item: StatsPostItem, views: Int32, reactions: Int32, forwards: Int32, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.message = message
|
self.peer = peer
|
||||||
|
self.item = item
|
||||||
self.views = views
|
self.views = views
|
||||||
|
self.reactions = reactions
|
||||||
self.forwards = forwards
|
self.forwards = forwards
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.style = style
|
self.style = style
|
||||||
@ -79,7 +85,7 @@ public class StatsMessageItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
private let badgeFont = Font.regular(15.0)
|
private let badgeFont = Font.regular(15.0)
|
||||||
|
|
||||||
public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
final class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -96,9 +102,14 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private var nonExtractedRect: CGRect?
|
private var nonExtractedRect: CGRect?
|
||||||
|
|
||||||
let contentImageNode: TransformImageNode
|
let contentImageNode: TransformImageNode
|
||||||
|
var storyIndicator: ComponentView<Empty>?
|
||||||
let titleNode: TextNode
|
let titleNode: TextNode
|
||||||
let labelNode: TextNode
|
let labelNode: TextNode
|
||||||
let viewsNode: TextNode
|
let viewsNode: TextNode
|
||||||
|
|
||||||
|
let reactionsIconNode: ASImageNode
|
||||||
|
let reactionsNode: TextNode
|
||||||
|
let forwardsIconNode: ASImageNode
|
||||||
let forwardsNode: TextNode
|
let forwardsNode: TextNode
|
||||||
|
|
||||||
private let activateArea: AccessibilityAreaNode
|
private let activateArea: AccessibilityAreaNode
|
||||||
@ -152,6 +163,15 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.forwardsNode = TextNode()
|
self.forwardsNode = TextNode()
|
||||||
self.forwardsNode.isUserInteractionEnabled = false
|
self.forwardsNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.forwardsIconNode = ASImageNode()
|
||||||
|
self.forwardsIconNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.reactionsNode = TextNode()
|
||||||
|
self.reactionsNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.reactionsIconNode = ASImageNode()
|
||||||
|
self.reactionsIconNode.displaysAsynchronously = false
|
||||||
|
|
||||||
self.highlightedBackgroundNode = ASDisplayNode()
|
self.highlightedBackgroundNode = ASDisplayNode()
|
||||||
self.highlightedBackgroundNode.isLayerBacked = true
|
self.highlightedBackgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -172,6 +192,9 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.offsetContainerNode.addSubnode(self.labelNode)
|
self.offsetContainerNode.addSubnode(self.labelNode)
|
||||||
self.countersContainerNode.addSubnode(self.viewsNode)
|
self.countersContainerNode.addSubnode(self.viewsNode)
|
||||||
self.countersContainerNode.addSubnode(self.forwardsNode)
|
self.countersContainerNode.addSubnode(self.forwardsNode)
|
||||||
|
self.countersContainerNode.addSubnode(self.forwardsIconNode)
|
||||||
|
self.countersContainerNode.addSubnode(self.reactionsNode)
|
||||||
|
self.countersContainerNode.addSubnode(self.reactionsIconNode)
|
||||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||||
|
|
||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
@ -200,8 +223,8 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
transition.updateAlpha(node: strongSelf.countersContainerNode, alpha: isExtracted ? 0.0 : 1.0)
|
transition.updateAlpha(node: strongSelf.countersContainerNode, alpha: isExtracted ? 0.0 : 1.0)
|
||||||
|
|
||||||
transition.updateSublayerTransformOffset(layer: strongSelf.countersContainerNode.layer, offset: CGPoint(x: isExtracted ? -24.0 : 0.0, y: 0.0))
|
transition.updateSublayerTransformOffset(layer: strongSelf.countersContainerNode.layer, offset: CGPoint(x: isExtracted ? -16.0 : 0.0, y: 0.0))
|
||||||
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 12.0 : 0.0, y: 0.0))
|
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 16.0 : 0.0, y: 0.0))
|
||||||
|
|
||||||
transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
|
transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
|
||||||
if !isExtracted {
|
if !isExtracted {
|
||||||
@ -215,6 +238,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
||||||
let makeViewsLayout = TextNode.asyncLayout(self.viewsNode)
|
let makeViewsLayout = TextNode.asyncLayout(self.viewsNode)
|
||||||
|
let makeReactionsLayout = TextNode.asyncLayout(self.reactionsNode)
|
||||||
let makeForwardsLayout = TextNode.asyncLayout(self.forwardsNode)
|
let makeForwardsLayout = TextNode.asyncLayout(self.forwardsNode)
|
||||||
|
|
||||||
let currentItem = self.item
|
let currentItem = self.item
|
||||||
@ -236,67 +260,100 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
let leftInset = 16.0 + params.leftInset
|
let leftInset = 16.0 + params.leftInset
|
||||||
let rightInset = 16.0 + params.rightInset
|
let rightInset = 16.0 + params.rightInset
|
||||||
var totalLeftInset = leftInset
|
var totalLeftInset = leftInset
|
||||||
let additionalRightInset: CGFloat = 128.0
|
|
||||||
|
|
||||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
let titleFont = Font.semibold(item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
let labelFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 13.0 / 17.0))
|
||||||
|
|
||||||
let presentationData = item.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = item.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let contentKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: .firstLast, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId)
|
|
||||||
var text = !item.message.text.isEmpty ? item.message.text : stringForMediaKind(contentKind, strings: item.presentationData.strings).0.string
|
|
||||||
text = foldLineBreaks(text)
|
|
||||||
|
|
||||||
|
var text: String
|
||||||
var contentImageMedia: Media?
|
var contentImageMedia: Media?
|
||||||
for media in item.message.media {
|
let timestamp: Int32
|
||||||
if let image = media as? TelegramMediaImage {
|
|
||||||
contentImageMedia = image
|
switch item.item {
|
||||||
break
|
case let .message(message):
|
||||||
} else if let file = media as? TelegramMediaFile {
|
let contentKind: MessageContentKind
|
||||||
if file.isVideo && !file.isInstantVideo {
|
contentKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: item.presentationData.strings, nameDisplayOrder: .firstLast, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId)
|
||||||
contentImageMedia = file
|
text = !message.text.isEmpty ? message.text : stringForMediaKind(contentKind, strings: item.presentationData.strings).0.string
|
||||||
break
|
|
||||||
}
|
for media in message.media {
|
||||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
if let image = media as? TelegramMediaImage {
|
||||||
if let image = content.image {
|
|
||||||
contentImageMedia = image
|
contentImageMedia = image
|
||||||
break
|
break
|
||||||
} else if let file = content.file {
|
} else if let file = media as? TelegramMediaFile {
|
||||||
if file.isVideo && !file.isInstantVideo {
|
if file.isVideo && !file.isInstantVideo {
|
||||||
contentImageMedia = file
|
contentImageMedia = file
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
||||||
|
if let image = content.image {
|
||||||
|
contentImageMedia = image
|
||||||
|
break
|
||||||
|
} else if let file = content.file {
|
||||||
|
if file.isVideo && !file.isInstantVideo {
|
||||||
|
contentImageMedia = file
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
timestamp = message.timestamp
|
||||||
|
case let .story(story):
|
||||||
|
text = item.presentationData.strings.Message_Story
|
||||||
|
timestamp = story.timestamp
|
||||||
|
if let image = story.media._asMedia() as? TelegramMediaImage {
|
||||||
|
contentImageMedia = image
|
||||||
|
break
|
||||||
|
} else if let file = story.media._asMedia() as? TelegramMediaFile {
|
||||||
|
contentImageMedia = file
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text = foldLineBreaks(text)
|
||||||
|
|
||||||
if let _ = contentImageMedia {
|
if let _ = contentImageMedia {
|
||||||
totalLeftInset += 48.0
|
totalLeftInset += 46.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
||||||
if let contentImageMedia = contentImageMedia {
|
if let contentImageMedia = contentImageMedia {
|
||||||
if let currentContentImageMedia = currentContentImageMedia, contentImageMedia.isSemanticallyEqual(to: currentContentImageMedia) {
|
if let currentContentImageMedia = currentContentImageMedia, contentImageMedia.isSemanticallyEqual(to: currentContentImageMedia) {
|
||||||
} else {
|
} else {
|
||||||
if let image = contentImageMedia as? TelegramMediaImage {
|
switch item.item {
|
||||||
updateImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: image))
|
case let .message(message):
|
||||||
} else if let file = contentImageMedia as? TelegramMediaFile {
|
if let image = contentImageMedia as? TelegramMediaImage {
|
||||||
updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), videoReference: .message(message: MessageReference(item.message), media: file), autoFetchFullSizeThumbnail: true)
|
updateImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image))
|
||||||
|
} else if let file = contentImageMedia as? TelegramMediaFile {
|
||||||
|
updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file), autoFetchFullSizeThumbnail: true)
|
||||||
|
}
|
||||||
|
case let .story(story):
|
||||||
|
if let peerReference = PeerReference(item.peer) {
|
||||||
|
if let image = contentImageMedia as? TelegramMediaImage {
|
||||||
|
updateImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(item.peer.id), photoReference: .story(peer: peerReference, id: story.id, media: image))
|
||||||
|
} else if let file = contentImageMedia as? TelegramMediaFile {
|
||||||
|
updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(item.peer.id), videoReference: .story(peer: peerReference, id: story.id, media: file), autoFetchFullSizeThumbnail: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - totalLeftInset - rightInset - additionalRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
|
||||||
|
|
||||||
let labelFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 13.0 / 17.0))
|
|
||||||
|
|
||||||
let label = stringForMediumDate(timestamp: item.message.timestamp, strings: item.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
|
||||||
|
|
||||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: label, font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - totalLeftInset - rightInset - additionalRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
|
||||||
|
|
||||||
let (viewsLayout, viewsApply) = makeViewsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageViews(item.views), font: labelFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
let (viewsLayout, viewsApply) = makeViewsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageViews(item.views), font: labelFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let (forwardsLayout, forwardsApply) = makeForwardsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageForwards(item.forwards), font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
let reactions = item.reactions > 0 ? compactNumericCountString(Int(item.reactions), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) : ""
|
||||||
|
let (reactionsLayout, reactionsApply) = makeReactionsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: reactions, font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let verticalInset: CGFloat = 11.0
|
let forwards = item.forwards > 0 ? compactNumericCountString(Int(item.forwards), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) : ""
|
||||||
|
let (forwardsLayout, forwardsApply) = makeForwardsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: forwards, font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let additionalRightInset = max(viewsLayout.size.width, reactionsLayout.size.width + forwardsLayout.size.width + 36.0) + 8.0
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - totalLeftInset - rightInset - additionalRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let label = stringForMediumDate(timestamp: timestamp, strings: item.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
|
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: label, font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - totalLeftInset - rightInset - additionalRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let verticalInset: CGFloat = 10.0
|
||||||
let titleSpacing: CGFloat = 3.0
|
let titleSpacing: CGFloat = 3.0
|
||||||
|
|
||||||
let height: CGFloat = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + labelLayout.size.height
|
let height: CGFloat = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + labelLayout.size.height
|
||||||
@ -318,8 +375,14 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
|
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
let themeUpdated = strongSelf.item?.presentationData.theme !== item.presentationData.theme
|
||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
strongSelf.forwardsIconNode.image = PresentationResourcesItemList.statsForwardsIcon(item.presentationData.theme)
|
||||||
|
strongSelf.reactionsIconNode.image = PresentationResourcesItemList.statsReactionsIcon(item.presentationData.theme)
|
||||||
|
}
|
||||||
|
|
||||||
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
|
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
|
||||||
let extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
|
let extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
|
||||||
strongSelf.extractedRect = extractedRect
|
strongSelf.extractedRect = extractedRect
|
||||||
@ -357,13 +420,21 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
dimensions = contentImageMedia.dimensions?.cgSize
|
dimensions = contentImageMedia.dimensions?.cgSize
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentImageSize = CGSize(width: 40.0, height: 40.0)
|
var contentImageSize = CGSize(width: 40.0, height: 40.0)
|
||||||
|
var contentImageInset = leftInset - 6.0
|
||||||
if let dimensions = dimensions {
|
if let dimensions = dimensions {
|
||||||
let makeImageLayout = strongSelf.contentImageNode.asyncLayout()
|
let makeImageLayout = strongSelf.contentImageNode.asyncLayout()
|
||||||
let imageSize = contentImageSize
|
|
||||||
|
|
||||||
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(radius: 4.0), imageSize: dimensions.aspectFilled(imageSize), boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
let cornerRadius: CGFloat
|
||||||
|
if case .story = item.item {
|
||||||
|
contentImageInset += 3.0
|
||||||
|
contentImageSize = CGSize(width: 34.0, height: 34.0)
|
||||||
|
cornerRadius = contentImageSize.width / 2.0
|
||||||
|
} else {
|
||||||
|
cornerRadius = 6.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(radius: cornerRadius), imageSize: dimensions.aspectFilled(contentImageSize), boundingSize: contentImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||||
applyImageLayout()
|
applyImageLayout()
|
||||||
|
|
||||||
if let updateImageSignal = updateImageSignal {
|
if let updateImageSignal = updateImageSignal {
|
||||||
@ -384,6 +455,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
let _ = labelApply()
|
let _ = labelApply()
|
||||||
let _ = viewsApply()
|
let _ = viewsApply()
|
||||||
let _ = forwardsApply()
|
let _ = forwardsApply()
|
||||||
|
let _ = reactionsApply()
|
||||||
|
|
||||||
switch item.style {
|
switch item.style {
|
||||||
case .plain:
|
case .plain:
|
||||||
@ -427,7 +499,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
let bottomStripeInset: CGFloat
|
let bottomStripeInset: CGFloat
|
||||||
switch neighbors.bottom {
|
switch neighbors.bottom {
|
||||||
case .sameSection(false):
|
case .sameSection(false):
|
||||||
bottomStripeInset = leftInset
|
bottomStripeInset = totalLeftInset
|
||||||
strongSelf.bottomStripeNode.isHidden = false
|
strongSelf.bottomStripeNode.isHidden = false
|
||||||
default:
|
default:
|
||||||
bottomStripeInset = 0.0
|
bottomStripeInset = 0.0
|
||||||
@ -443,22 +515,106 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentImageFrame = CGRect(origin: CGPoint(x: leftInset, y: floorToScreenPixels((height - contentImageSize.height) / 2.0)), size: contentImageSize)
|
let contentImageFrame = CGRect(origin: CGPoint(x: contentImageInset, y: floorToScreenPixels((height - contentImageSize.height) / 2.0)), size: contentImageSize)
|
||||||
strongSelf.contentImageNode.frame = contentImageFrame
|
strongSelf.contentImageNode.frame = contentImageFrame
|
||||||
|
|
||||||
let titleFrame = CGRect(origin: CGPoint(x: totalLeftInset, y: 11.0), size: titleLayout.size)
|
let titleFrame = CGRect(origin: CGPoint(x: totalLeftInset, y: 9.0), size: titleLayout.size)
|
||||||
strongSelf.titleNode.frame = titleFrame
|
strongSelf.titleNode.frame = titleFrame
|
||||||
|
|
||||||
let labelFrame = CGRect(origin: CGPoint(x: totalLeftInset, y: titleFrame.maxY + titleSpacing), size: labelLayout.size)
|
let labelFrame = CGRect(origin: CGPoint(x: totalLeftInset, y: titleFrame.maxY + titleSpacing), size: labelLayout.size)
|
||||||
strongSelf.labelNode.frame = labelFrame
|
strongSelf.labelNode.frame = labelFrame
|
||||||
|
|
||||||
let viewsFrame = CGRect(origin: CGPoint(x: params.width - rightInset - viewsLayout.size.width, y: 15.0), size: viewsLayout.size)
|
let viewsFrame = CGRect(origin: CGPoint(x: params.width - rightInset - viewsLayout.size.width, y: 13.0), size: viewsLayout.size)
|
||||||
strongSelf.viewsNode.frame = viewsFrame
|
strongSelf.viewsNode.frame = viewsFrame
|
||||||
|
|
||||||
let forwardsFrame = CGRect(origin: CGPoint(x: params.width - rightInset - forwardsLayout.size.width, y: titleFrame.maxY + titleSpacing), size: forwardsLayout.size)
|
let iconSpacing: CGFloat = 3.0 - UIScreenPixel
|
||||||
strongSelf.forwardsNode.frame = forwardsFrame
|
|
||||||
|
var rightContentInset: CGFloat = rightInset
|
||||||
|
if forwardsLayout.size.width > 0.0 {
|
||||||
|
strongSelf.forwardsIconNode.isHidden = false
|
||||||
|
strongSelf.forwardsNode.isHidden = false
|
||||||
|
|
||||||
|
let forwardsFrame = CGRect(origin: CGPoint(x: params.width - rightContentInset - forwardsLayout.size.width, y: titleFrame.maxY + titleSpacing), size: forwardsLayout.size)
|
||||||
|
strongSelf.forwardsNode.frame = forwardsFrame
|
||||||
|
|
||||||
|
if let icon = strongSelf.forwardsIconNode.image {
|
||||||
|
let forwardsIconFrame = CGRect(origin: CGPoint(x: params.width - rightContentInset - forwardsLayout.size.width - icon.size.width - iconSpacing, y: titleFrame.maxY + titleSpacing - 2.0 + UIScreenPixel), size: icon.size)
|
||||||
|
strongSelf.forwardsIconNode.frame = forwardsIconFrame
|
||||||
|
|
||||||
|
rightContentInset += forwardsIconFrame.width + forwardsFrame.width + iconSpacing
|
||||||
|
}
|
||||||
|
rightContentInset += 10.0
|
||||||
|
} else {
|
||||||
|
strongSelf.forwardsIconNode.isHidden = true
|
||||||
|
strongSelf.forwardsNode.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if reactionsLayout.size.width > 0.0 {
|
||||||
|
strongSelf.reactionsIconNode.isHidden = false
|
||||||
|
strongSelf.reactionsNode.isHidden = false
|
||||||
|
|
||||||
|
let reactionsFrame = CGRect(origin: CGPoint(x: params.width - rightContentInset - reactionsLayout.size.width, y: titleFrame.maxY + titleSpacing), size: reactionsLayout.size)
|
||||||
|
strongSelf.reactionsNode.frame = reactionsFrame
|
||||||
|
|
||||||
|
if let icon = strongSelf.reactionsIconNode.image {
|
||||||
|
let reactionsIconFrame = CGRect(origin: CGPoint(x: params.width - rightContentInset - reactionsLayout.size.width - icon.size.width - iconSpacing, y: titleFrame.maxY + titleSpacing - 2.0 + UIScreenPixel), size: icon.size)
|
||||||
|
strongSelf.reactionsIconNode.frame = reactionsIconFrame
|
||||||
|
|
||||||
|
rightContentInset += reactionsIconFrame.width + reactionsFrame.width + iconSpacing
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strongSelf.reactionsIconNode.isHidden = true
|
||||||
|
strongSelf.reactionsNode.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: height + UIScreenPixel))
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: height + UIScreenPixel))
|
||||||
|
|
||||||
|
if case .story = item.item {
|
||||||
|
let lineWidth: CGFloat = 1.5
|
||||||
|
let imageSize = CGSize(width: contentImageFrame.width + 6.0, height: contentImageFrame.height + 6.0)
|
||||||
|
let indicatorSize = CGSize(width: imageSize.width - lineWidth * 4.0, height: imageSize.height - lineWidth * 4.0)
|
||||||
|
|
||||||
|
let storyIndicator: ComponentView<Empty>
|
||||||
|
let indicatorTransition: Transition = .immediate
|
||||||
|
if let current = strongSelf.storyIndicator {
|
||||||
|
storyIndicator = current
|
||||||
|
} else {
|
||||||
|
storyIndicator = ComponentView()
|
||||||
|
strongSelf.storyIndicator = storyIndicator
|
||||||
|
}
|
||||||
|
let _ = storyIndicator.update(
|
||||||
|
transition: indicatorTransition,
|
||||||
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
|
hasUnseen: true,
|
||||||
|
hasUnseenCloseFriendsItems: false,
|
||||||
|
colors: AvatarStoryIndicatorComponent.Colors(
|
||||||
|
unseenColors: item.presentationData.theme.chatList.storyUnseenColors.array,
|
||||||
|
unseenCloseFriendsColors: item.presentationData.theme.chatList.storyUnseenPrivateColors.array,
|
||||||
|
seenColors: item.presentationData.theme.chatList.storySeenColors.array
|
||||||
|
),
|
||||||
|
activeLineWidth: lineWidth,
|
||||||
|
inactiveLineWidth: lineWidth,
|
||||||
|
counters: AvatarStoryIndicatorComponent.Counters(
|
||||||
|
totalCount: 1,
|
||||||
|
unseenCount: 1
|
||||||
|
),
|
||||||
|
progress: nil
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: indicatorSize
|
||||||
|
)
|
||||||
|
if let storyIndicatorView = storyIndicator.view {
|
||||||
|
if storyIndicatorView.superview == nil {
|
||||||
|
strongSelf.offsetContainerNode.view.addSubview(storyIndicatorView)
|
||||||
|
}
|
||||||
|
indicatorTransition.setFrame(view: storyIndicatorView, frame: CGRect(origin: CGPoint(x: contentImageFrame.midX - indicatorSize.width / 2.0, y: contentImageFrame.midY - indicatorSize.height / 2.0), size: indicatorSize))
|
||||||
|
}
|
||||||
|
} else if let storyIndicator = strongSelf.storyIndicator {
|
||||||
|
if let storyIndicatorView = storyIndicator.view {
|
||||||
|
storyIndicatorView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
strongSelf.storyIndicator = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
106
submodules/StatisticsUI/Sources/StoryIconNode.swift
Normal file
106
submodules/StatisticsUI/Sources/StoryIconNode.swift
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import Foundation
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import ComponentFlow
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import PhotoResources
|
||||||
|
import AvatarStoryIndicatorComponent
|
||||||
|
import AccountContext
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
|
final class StoryIconNode: ASDisplayNode {
|
||||||
|
private let imageNode = TransformImageNode()
|
||||||
|
private let storyIndicator = ComponentView<Empty>()
|
||||||
|
|
||||||
|
init(context: AccountContext, theme: PresentationTheme, peer: Peer, storyItem: EngineStoryItem) {
|
||||||
|
self.imageNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
|
let imageSize = CGSize(width: 30.0, height: 30.0)
|
||||||
|
let size = CGSize(width: 36.0, height: 36.0)
|
||||||
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
|
|
||||||
|
self.imageNode.frame = bounds.insetBy(dx: 3.0, dy: 3.0)
|
||||||
|
self.frame = bounds
|
||||||
|
|
||||||
|
let media: Media?
|
||||||
|
switch storyItem.media {
|
||||||
|
case let .image(image):
|
||||||
|
media = image
|
||||||
|
case let .file(file):
|
||||||
|
media = file
|
||||||
|
default:
|
||||||
|
media = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
||||||
|
var dimensions: CGSize?
|
||||||
|
if let peerReference = PeerReference(peer), let media {
|
||||||
|
if let image = media as? TelegramMediaImage {
|
||||||
|
updateImageSignal = mediaGridMessagePhoto(account: context.account, userLocation: .peer(peer.id), photoReference: .story(peer: peerReference, id: storyItem.id, media: image))
|
||||||
|
dimensions = largestRepresentationForPhoto(image)?.dimensions.cgSize
|
||||||
|
} else if let file = media as? TelegramMediaFile {
|
||||||
|
updateImageSignal = mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(peer.id), videoReference: .story(peer: peerReference, id: storyItem.id, media: file), autoFetchFullSizeThumbnail: true)
|
||||||
|
dimensions = file.dimensions?.cgSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let updateImageSignal {
|
||||||
|
self.imageNode.setSignal(updateImageSignal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let dimensions {
|
||||||
|
let cornerRadius = imageSize.width / 2.0
|
||||||
|
let makeImageLayout = self.imageNode.asyncLayout()
|
||||||
|
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(radius: cornerRadius), imageSize: dimensions.aspectFilled(imageSize), boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||||
|
applyImageLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
let lineWidth: CGFloat = 1.5
|
||||||
|
let indicatorSize = CGSize(width: size.width - lineWidth * 4.0, height: size.height - lineWidth * 4.0)
|
||||||
|
|
||||||
|
let _ = self.storyIndicator.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
|
hasUnseen: true,
|
||||||
|
hasUnseenCloseFriendsItems: false,
|
||||||
|
colors: AvatarStoryIndicatorComponent.Colors(
|
||||||
|
unseenColors: theme.chatList.storyUnseenColors.array,
|
||||||
|
unseenCloseFriendsColors: theme.chatList.storyUnseenPrivateColors.array,
|
||||||
|
seenColors: theme.chatList.storySeenColors.array
|
||||||
|
),
|
||||||
|
activeLineWidth: lineWidth,
|
||||||
|
inactiveLineWidth: lineWidth,
|
||||||
|
counters: AvatarStoryIndicatorComponent.Counters(
|
||||||
|
totalCount: 1,
|
||||||
|
unseenCount: 1
|
||||||
|
),
|
||||||
|
progress: nil
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: indicatorSize
|
||||||
|
)
|
||||||
|
if let storyIndicatorView = self.storyIndicator.view {
|
||||||
|
storyIndicatorView.frame = CGRect(origin: CGPoint(x: bounds.midX - indicatorSize.width / 2.0, y: bounds.midY - indicatorSize.height / 2.0), size: indicatorSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
if let storyIndicatorView = self.storyIndicator.view {
|
||||||
|
if storyIndicatorView.superview == nil {
|
||||||
|
self.view.addSubview(storyIndicatorView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
|
return CGSize(width: 36.0, height: 36.0)
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,14 @@ public struct ChannelStatsMessageInteractions: Equatable {
|
|||||||
public let messageId: MessageId
|
public let messageId: MessageId
|
||||||
public let views: Int32
|
public let views: Int32
|
||||||
public let forwards: Int32
|
public let forwards: Int32
|
||||||
|
public let reactions: Int32
|
||||||
|
|
||||||
|
public init(messageId: MessageId, views: Int32, forwards: Int32, reactions: Int32) {
|
||||||
|
self.messageId = messageId
|
||||||
|
self.views = views
|
||||||
|
self.forwards = forwards
|
||||||
|
self.reactions = reactions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class ChannelStats: Equatable {
|
public final class ChannelStats: Equatable {
|
||||||
@ -1143,7 +1151,7 @@ extension ChannelStatsMessageInteractions {
|
|||||||
init(apiMessageInteractionCounters: Api.MessageInteractionCounters, peerId: PeerId) {
|
init(apiMessageInteractionCounters: Api.MessageInteractionCounters, peerId: PeerId) {
|
||||||
switch apiMessageInteractionCounters {
|
switch apiMessageInteractionCounters {
|
||||||
case let .messageInteractionCounters(msgId, views, forwards):
|
case let .messageInteractionCounters(msgId, views, forwards):
|
||||||
self = ChannelStatsMessageInteractions(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: msgId), views: views, forwards: forwards)
|
self = ChannelStatsMessageInteractions(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: msgId), views: views, forwards: forwards, reactions: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,10 @@ public final class PresentationThemeGradientColors {
|
|||||||
return (self.topColor, self.bottomColor)
|
return (self.topColor, self.bottomColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var array: [UIColor] {
|
||||||
|
return [self.topColor, self.bottomColor]
|
||||||
|
}
|
||||||
|
|
||||||
public func withUpdated(topColor: UIColor? = nil, bottomColor: UIColor? = nil) -> PresentationThemeGradientColors {
|
public func withUpdated(topColor: UIColor? = nil, bottomColor: UIColor? = nil) -> PresentationThemeGradientColors {
|
||||||
return PresentationThemeGradientColors(topColor: topColor ?? self.topColor, bottomColor: bottomColor ?? self.bottomColor)
|
return PresentationThemeGradientColors(topColor: topColor ?? self.topColor, bottomColor: bottomColor ?? self.bottomColor)
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,9 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case itemListTopicArrowIcon
|
case itemListTopicArrowIcon
|
||||||
case itemListAddBoostsIcon
|
case itemListAddBoostsIcon
|
||||||
|
|
||||||
|
case statsReactionsIcon
|
||||||
|
case statsForwardsIcon
|
||||||
|
|
||||||
case itemListVoiceCallIcon
|
case itemListVoiceCallIcon
|
||||||
case itemListVideoCallIcon
|
case itemListVideoCallIcon
|
||||||
|
|
||||||
|
@ -329,4 +329,16 @@ public struct PresentationResourcesItemList {
|
|||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/TopicArrowIcon"), color: theme.list.itemSecondaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/TopicArrowIcon"), color: theme.list.itemSecondaryTextColor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func statsReactionsIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.statsReactionsIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chart/Reactions"), color: theme.list.itemSecondaryTextColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func statsForwardsIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.statsForwardsIcon.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chart/Forwards"), color: theme.list.itemSecondaryTextColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1123,7 +1123,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
component: MultilineTextComponent(
|
component: MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(string: durationString, font: Font.with(size: 21.0, design: .camera), textColor: controlsTintColor)),
|
text: .plain(NSAttributedString(string: durationString, font: Font.with(size: 21.0, design: .camera), textColor: controlsTintColor)),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
textShadowColor: UIColor(rgb: 0x000000, alpha: 0.2)
|
textShadowColor: controlsTintColor == .black ? .clear : UIColor(rgb: 0x000000, alpha: 0.2)
|
||||||
),
|
),
|
||||||
availableSize: context.availableSize,
|
availableSize: context.availableSize,
|
||||||
transition: context.transition
|
transition: context.transition
|
||||||
|
@ -31,6 +31,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||||
"//submodules/TelegramUI/Components/Utils/RoundedRectWithTailPath",
|
"//submodules/TelegramUI/Components/Utils/RoundedRectWithTailPath",
|
||||||
"//submodules/Components/MultilineTextComponent",
|
"//submodules/Components/MultilineTextComponent",
|
||||||
|
"//submodules/Components/BundleIconComponent",
|
||||||
"//submodules/ChatMessageBackground",
|
"//submodules/ChatMessageBackground",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
|
@ -561,6 +561,7 @@ private final class PeerInfoInteraction {
|
|||||||
let displayTopicsLimited: (TopicsLimitedReason) -> Void
|
let displayTopicsLimited: (TopicsLimitedReason) -> Void
|
||||||
let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void
|
let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void
|
||||||
let openBotApp: (AttachMenuBot) -> Void
|
let openBotApp: (AttachMenuBot) -> Void
|
||||||
|
let openEditing: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
openUsername: @escaping (String) -> Void,
|
openUsername: @escaping (String) -> Void,
|
||||||
@ -614,7 +615,8 @@ private final class PeerInfoInteraction {
|
|||||||
toggleForumTopics: @escaping (Bool) -> Void,
|
toggleForumTopics: @escaping (Bool) -> Void,
|
||||||
displayTopicsLimited: @escaping (TopicsLimitedReason) -> Void,
|
displayTopicsLimited: @escaping (TopicsLimitedReason) -> Void,
|
||||||
openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void,
|
openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void,
|
||||||
openBotApp: @escaping (AttachMenuBot) -> Void
|
openBotApp: @escaping (AttachMenuBot) -> Void,
|
||||||
|
openEditing: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.openUsername = openUsername
|
self.openUsername = openUsername
|
||||||
self.openPhone = openPhone
|
self.openPhone = openPhone
|
||||||
@ -668,6 +670,7 @@ private final class PeerInfoInteraction {
|
|||||||
self.displayTopicsLimited = displayTopicsLimited
|
self.displayTopicsLimited = displayTopicsLimited
|
||||||
self.openPeerMention = openPeerMention
|
self.openPeerMention = openPeerMention
|
||||||
self.openBotApp = openBotApp
|
self.openBotApp = openBotApp
|
||||||
|
self.openEditing = openEditing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,6 +1211,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
let ItemAdmins = 6
|
let ItemAdmins = 6
|
||||||
let ItemMembers = 7
|
let ItemMembers = 7
|
||||||
let ItemMemberRequests = 8
|
let ItemMemberRequests = 8
|
||||||
|
let ItemEdit = 9
|
||||||
|
|
||||||
if let _ = data.threadData {
|
if let _ = data.threadData {
|
||||||
let mainUsername: String
|
let mainUsername: String
|
||||||
@ -1358,6 +1362,10 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
interaction.openParticipantsSection(.memberRequests)
|
interaction.openParticipantsSection(.memberRequests)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items[.peerMembers]!.append(PeerInfoScreenDisclosureItem(id: ItemEdit, label: .none, text: presentationData.strings.Channel_Info_Settings, icon: UIImage(bundleImageName: "Chat/Info/SettingsIcon"), action: {
|
||||||
|
interaction.openEditing()
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2425,6 +2433,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
},
|
},
|
||||||
openBotApp: { [weak self] bot in
|
openBotApp: { [weak self] bot in
|
||||||
self?.openBotApp(bot)
|
self?.openBotApp(bot)
|
||||||
|
},
|
||||||
|
openEditing: { [weak self] in
|
||||||
|
self?.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"info" : {
|
"info" : {
|
||||||
"version" : 1,
|
"author" : "xcode",
|
||||||
"author" : "xcode"
|
"version" : 1
|
||||||
},
|
},
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"provides-namespace" : true
|
"provides-namespace" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Chart/Forwards.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chart/Forwards.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "arrowshape_18.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
148
submodules/TelegramUI/Images.xcassets/Chart/Forwards.imageset/arrowshape_18.pdf
vendored
Normal file
148
submodules/TelegramUI/Images.xcassets/Chart/Forwards.imageset/arrowshape_18.pdf
vendored
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 1.809143 2.532226 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.381874 3.080939 m
|
||||||
|
1.812524 5.409000 3.194212 8.717773 7.569556 8.717773 c
|
||||||
|
7.569556 9.917774 l
|
||||||
|
7.569556 10.446452 l
|
||||||
|
7.569556 10.480809 l
|
||||||
|
7.569556 10.707834 l
|
||||||
|
7.569556 11.144928 7.569556 11.363475 7.657061 11.467960 c
|
||||||
|
7.733040 11.558682 7.847383 11.608219 7.965533 11.601600 c
|
||||||
|
8.101606 11.593976 8.261045 11.444503 8.579921 11.145556 c
|
||||||
|
8.745543 10.990285 l
|
||||||
|
8.770609 10.966786 l
|
||||||
|
13.102652 6.905496 l
|
||||||
|
13.265036 6.753260 13.346226 6.677144 13.376384 6.588246 c
|
||||||
|
13.402888 6.510118 13.402888 6.425430 13.376384 6.347302 c
|
||||||
|
13.346226 6.258403 13.265034 6.182286 13.102651 6.030052 c
|
||||||
|
8.770609 1.968762 l
|
||||||
|
8.745543 1.945263 l
|
||||||
|
8.579920 1.789990 l
|
||||||
|
8.261045 1.491045 8.101606 1.341572 7.965533 1.333949 c
|
||||||
|
7.847383 1.327330 7.733040 1.376866 7.657061 1.467588 c
|
||||||
|
7.569556 1.572074 7.569556 1.790621 7.569556 2.227714 c
|
||||||
|
7.569556 2.454739 l
|
||||||
|
7.569556 2.489097 l
|
||||||
|
7.569556 3.017775 l
|
||||||
|
7.569556 4.217774 l
|
||||||
|
7.144288 4.217774 6.744702 4.192091 6.369556 4.145205 c
|
||||||
|
4.554104 3.918311 3.310977 3.194876 2.499113 2.482739 c
|
||||||
|
2.362022 2.362489 2.237234 2.242566 2.124057 2.125404 c
|
||||||
|
2.050126 2.048869 1.981147 1.973513 1.916941 1.900021 c
|
||||||
|
1.888999 1.868037 1.861959 1.836406 1.835807 1.805183 c
|
||||||
|
1.802983 1.765995 1.771556 1.727451 1.741497 1.689663 c
|
||||||
|
1.527425 1.420543 1.420391 1.285985 1.360707 1.277870 c
|
||||||
|
1.306377 1.270482 1.259393 1.288921 1.224590 1.331290 c
|
||||||
|
1.186357 1.377833 1.198391 1.535853 1.222459 1.851893 c
|
||||||
|
1.228173 1.926921 1.234867 2.005210 1.242695 2.086436 c
|
||||||
|
1.243798 2.097883 1.244923 2.109387 1.246072 2.120950 c
|
||||||
|
1.257281 2.233779 1.270675 2.352077 1.286657 2.475003 c
|
||||||
|
1.311591 2.666784 1.342823 2.869831 1.381874 3.080939 c
|
||||||
|
h
|
||||||
|
0.592504 2.179043 m
|
||||||
|
0.592526 2.179102 0.593651 2.180346 0.595821 2.182594 c
|
||||||
|
0.593566 2.180108 0.592482 2.178984 0.592504 2.179043 c
|
||||||
|
h
|
||||||
|
6.369556 2.934145 m
|
||||||
|
6.369556 2.227714 l
|
||||||
|
6.369556 2.216033 6.369552 2.204231 6.369547 2.192325 c
|
||||||
|
6.369482 2.005756 6.369406 1.793388 6.385262 1.616055 c
|
||||||
|
6.399108 1.461200 6.439729 1.052163 6.737077 0.697114 c
|
||||||
|
7.056188 0.316081 7.536427 0.108026 8.032658 0.135827 c
|
||||||
|
8.495048 0.161733 8.821238 0.411856 8.943680 0.507667 c
|
||||||
|
9.083900 0.617389 9.238787 0.762698 9.374854 0.890351 c
|
||||||
|
9.383532 0.898493 9.392133 0.906562 9.400649 0.914546 c
|
||||||
|
13.923381 5.154607 l
|
||||||
|
13.928342 5.159257 13.933517 5.164101 13.938882 5.169123 c
|
||||||
|
14.005202 5.231203 14.100604 5.320504 14.180048 5.408552 c
|
||||||
|
14.274767 5.513531 14.422819 5.696626 14.512774 5.961792 c
|
||||||
|
14.624091 6.289929 14.624091 6.645618 14.512774 6.973756 c
|
||||||
|
14.422819 7.238921 14.274767 7.422017 14.180048 7.526996 c
|
||||||
|
14.100601 7.615047 14.005195 7.704352 13.938873 7.766432 c
|
||||||
|
13.933511 7.771451 13.928339 7.776292 13.923381 7.780941 c
|
||||||
|
9.400650 12.021002 l
|
||||||
|
9.392125 12.028994 9.383514 12.037071 9.374827 12.045221 c
|
||||||
|
9.238766 12.172870 9.083892 12.318167 8.943680 12.427882 c
|
||||||
|
8.821238 12.523692 8.495049 12.773815 8.032658 12.799721 c
|
||||||
|
7.536427 12.827522 7.056188 12.619467 6.737077 12.238434 c
|
||||||
|
6.439729 11.883385 6.399108 11.474348 6.385262 11.319493 c
|
||||||
|
6.369406 11.142159 6.369482 10.929791 6.369547 10.743222 c
|
||||||
|
6.369552 10.731316 6.369556 10.719515 6.369556 10.707834 c
|
||||||
|
6.369556 9.839663 l
|
||||||
|
3.993418 9.518946 2.436784 8.247826 1.476669 6.720201 c
|
||||||
|
0.412234 5.026595 0.112609 3.081284 0.025924 1.943016 c
|
||||||
|
0.025268 1.934407 0.024604 1.925713 0.023934 1.916945 c
|
||||||
|
0.013668 1.782581 0.002083 1.630936 0.000289 1.508040 c
|
||||||
|
-0.000665 1.442641 -0.000246 1.333831 0.017544 1.213016 c
|
||||||
|
0.030832 1.122771 0.076845 0.837997 0.297327 0.569592 c
|
||||||
|
0.596399 0.205513 1.055517 0.025331 1.522386 0.088812 c
|
||||||
|
1.882774 0.137815 2.117930 0.331811 2.178427 0.381719 c
|
||||||
|
2.178911 0.382119 l
|
||||||
|
2.270915 0.458017 2.344114 0.537148 2.388324 0.586662 c
|
||||||
|
2.472725 0.681190 2.571892 0.805902 2.664181 0.921966 c
|
||||||
|
2.680620 0.942637 l
|
||||||
|
3.203021 1.599372 4.310469 2.634761 6.369556 2.934145 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
3854
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 18.000000 18.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000003944 00000 n
|
||||||
|
0000003967 00000 n
|
||||||
|
0000004140 00000 n
|
||||||
|
0000004214 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
4273
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chart/Reactions.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chart/Reactions.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "heart_18.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
95
submodules/TelegramUI/Images.xcassets/Chart/Reactions.imageset/heart_18.pdf
vendored
Normal file
95
submodules/TelegramUI/Images.xcassets/Chart/Reactions.imageset/heart_18.pdf
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 2.024963 2.215471 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 8.477227 m
|
||||||
|
0.000000 11.090064 1.837903 13.009529 4.216708 13.009529 c
|
||||||
|
5.378695 13.009529 6.314748 12.504827 6.976930 11.731193 c
|
||||||
|
7.642573 12.506644 8.575254 13.009529 9.739605 13.009529 c
|
||||||
|
12.119733 13.009529 13.950001 11.088655 13.950001 8.477227 c
|
||||||
|
13.950001 5.445473 11.442898 2.625515 7.886870 0.335408 c
|
||||||
|
7.883046 0.332945 l
|
||||||
|
7.883036 0.332960 l
|
||||||
|
7.773217 0.263408 7.639669 0.186707 7.499969 0.125453 c
|
||||||
|
7.373253 0.069893 7.182288 0.000000 6.975000 0.000000 c
|
||||||
|
6.768435 0.000000 6.577350 0.071704 6.454765 0.125453 c
|
||||||
|
6.317346 0.185706 6.184213 0.261022 6.074458 0.328291 c
|
||||||
|
6.063049 0.335283 l
|
||||||
|
6.063130 0.335408 l
|
||||||
|
2.507103 2.625515 0.000000 5.445473 0.000000 8.477227 c
|
||||||
|
h
|
||||||
|
4.216708 11.809529 m
|
||||||
|
2.568532 11.809529 1.200000 10.497311 1.200000 8.477227 c
|
||||||
|
1.200000 6.107325 3.209978 3.601517 6.707050 1.348038 c
|
||||||
|
6.790931 1.296850 6.870368 1.253510 6.936634 1.224454 c
|
||||||
|
6.952608 1.217450 6.966116 1.212033 6.977225 1.207909 c
|
||||||
|
6.988396 1.211988 7.002014 1.217401 7.018100 1.224454 c
|
||||||
|
7.083025 1.252921 7.160221 1.295694 7.239110 1.345563 c
|
||||||
|
10.738551 3.599682 12.750001 6.106457 12.750001 8.477227 c
|
||||||
|
12.750001 10.498720 11.386456 11.809529 9.739605 11.809529 c
|
||||||
|
8.743175 11.809529 7.985357 11.273088 7.501738 10.386451 c
|
||||||
|
7.396244 10.193047 7.193245 10.073009 6.972942 10.073765 c
|
||||||
|
6.752639 10.074521 6.550468 10.195948 6.446304 10.390072 c
|
||||||
|
5.975964 11.266614 5.213501 11.809529 4.216708 11.809529 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1521
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 18.000000 18.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000001611 00000 n
|
||||||
|
0000001634 00000 n
|
||||||
|
0000001807 00000 n
|
||||||
|
0000001881 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1940
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Info/SettingsIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Info/SettingsIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "settings_30.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
290
submodules/TelegramUI/Images.xcassets/Chat/Info/SettingsIcon.imageset/settings_30.pdf
vendored
Normal file
290
submodules/TelegramUI/Images.xcassets/Chat/Info/SettingsIcon.imageset/settings_30.pdf
vendored
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< /Type /XObject
|
||||||
|
/Length 2 0 R
|
||||||
|
/Group << /Type /Group
|
||||||
|
/S /Transparency
|
||||||
|
>>
|
||||||
|
/Subtype /Form
|
||||||
|
/Resources << >>
|
||||||
|
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
1.000000 0.584314 0.000000 scn
|
||||||
|
0.000000 18.799999 m
|
||||||
|
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||||
|
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||||
|
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||||
|
18.799999 30.000000 l
|
||||||
|
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||||
|
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||||
|
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||||
|
30.000000 11.200001 l
|
||||||
|
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||||
|
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||||
|
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||||
|
11.200000 0.000000 l
|
||||||
|
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||||
|
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||||
|
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||||
|
0.000000 18.799999 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 6.000000 9.000000 cm
|
||||||
|
1.000000 1.000000 1.000000 scn
|
||||||
|
17.000078 10.000000 m
|
||||||
|
17.552362 10.000000 18.000078 10.447716 18.000078 11.000000 c
|
||||||
|
18.000078 11.552285 17.552362 12.000000 17.000078 12.000000 c
|
||||||
|
1.000078 12.000000 l
|
||||||
|
0.447794 12.000000 0.000078 11.552285 0.000078 11.000000 c
|
||||||
|
0.000078 10.447716 0.447794 10.000000 1.000078 10.000000 c
|
||||||
|
17.000078 10.000000 l
|
||||||
|
h
|
||||||
|
17.000000 0.000078 m
|
||||||
|
17.552284 0.000078 18.000000 0.447793 18.000000 1.000078 c
|
||||||
|
18.000000 1.552363 17.552284 2.000078 17.000000 2.000078 c
|
||||||
|
1.000000 2.000078 l
|
||||||
|
0.447716 2.000078 0.000000 1.552363 0.000000 1.000078 c
|
||||||
|
0.000000 0.447793 0.447716 0.000078 1.000000 0.000078 c
|
||||||
|
17.000000 0.000078 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 6.000000 16.000000 cm
|
||||||
|
1.000000 0.584314 0.000000 scn
|
||||||
|
8.000000 4.000000 m
|
||||||
|
8.000000 1.790861 6.209139 0.000000 4.000000 0.000000 c
|
||||||
|
1.790861 0.000000 0.000000 1.790861 0.000000 4.000000 c
|
||||||
|
0.000000 6.209139 1.790861 8.000000 4.000000 8.000000 c
|
||||||
|
6.209139 8.000000 8.000000 6.209139 8.000000 4.000000 c
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
14.000000 20.000000 m
|
||||||
|
14.000000 17.790861 12.209139 16.000000 10.000000 16.000000 c
|
||||||
|
7.790861 16.000000 6.000000 17.790861 6.000000 20.000000 c
|
||||||
|
6.000000 22.209139 7.790861 24.000000 10.000000 24.000000 c
|
||||||
|
12.209139 24.000000 14.000000 22.209139 14.000000 20.000000 c
|
||||||
|
h
|
||||||
|
W*
|
||||||
|
n
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 6.000000 16.000000 cm
|
||||||
|
1.000000 1.000000 1.000000 scn
|
||||||
|
6.000000 4.000000 m
|
||||||
|
6.000000 2.895431 5.104569 2.000000 4.000000 2.000000 c
|
||||||
|
4.000000 -2.000000 l
|
||||||
|
7.313708 -2.000000 10.000000 0.686292 10.000000 4.000000 c
|
||||||
|
6.000000 4.000000 l
|
||||||
|
h
|
||||||
|
4.000000 2.000000 m
|
||||||
|
2.895431 2.000000 2.000000 2.895431 2.000000 4.000000 c
|
||||||
|
-2.000000 4.000000 l
|
||||||
|
-2.000000 0.686292 0.686292 -2.000000 4.000000 -2.000000 c
|
||||||
|
4.000000 2.000000 l
|
||||||
|
h
|
||||||
|
2.000000 4.000000 m
|
||||||
|
2.000000 5.104569 2.895431 6.000000 4.000000 6.000000 c
|
||||||
|
4.000000 10.000000 l
|
||||||
|
0.686292 10.000000 -2.000000 7.313708 -2.000000 4.000000 c
|
||||||
|
2.000000 4.000000 l
|
||||||
|
h
|
||||||
|
4.000000 6.000000 m
|
||||||
|
5.104569 6.000000 6.000000 5.104569 6.000000 4.000000 c
|
||||||
|
10.000000 4.000000 l
|
||||||
|
10.000000 7.313708 7.313708 10.000000 4.000000 10.000000 c
|
||||||
|
4.000000 6.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 16.000000 6.000000 cm
|
||||||
|
1.000000 0.584314 0.000000 scn
|
||||||
|
8.000000 4.000000 m
|
||||||
|
8.000000 1.790861 6.209139 0.000000 4.000000 0.000000 c
|
||||||
|
1.790861 0.000000 0.000000 1.790861 0.000000 4.000000 c
|
||||||
|
0.000000 6.209139 1.790861 8.000000 4.000000 8.000000 c
|
||||||
|
6.209139 8.000000 8.000000 6.209139 8.000000 4.000000 c
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
24.000000 10.000000 m
|
||||||
|
24.000000 7.790861 22.209139 6.000000 20.000000 6.000000 c
|
||||||
|
17.790861 6.000000 16.000000 7.790861 16.000000 10.000000 c
|
||||||
|
16.000000 12.209139 17.790861 14.000000 20.000000 14.000000 c
|
||||||
|
22.209139 14.000000 24.000000 12.209139 24.000000 10.000000 c
|
||||||
|
h
|
||||||
|
W*
|
||||||
|
n
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 16.000000 6.000000 cm
|
||||||
|
1.000000 1.000000 1.000000 scn
|
||||||
|
6.000000 4.000000 m
|
||||||
|
6.000000 2.895431 5.104569 2.000000 4.000000 2.000000 c
|
||||||
|
4.000000 -2.000000 l
|
||||||
|
7.313708 -2.000000 10.000000 0.686292 10.000000 4.000000 c
|
||||||
|
6.000000 4.000000 l
|
||||||
|
h
|
||||||
|
4.000000 2.000000 m
|
||||||
|
2.895431 2.000000 2.000000 2.895431 2.000000 4.000000 c
|
||||||
|
-2.000000 4.000000 l
|
||||||
|
-2.000000 0.686292 0.686292 -2.000000 4.000000 -2.000000 c
|
||||||
|
4.000000 2.000000 l
|
||||||
|
h
|
||||||
|
2.000000 4.000000 m
|
||||||
|
2.000000 5.104569 2.895431 6.000000 4.000000 6.000000 c
|
||||||
|
4.000000 10.000000 l
|
||||||
|
0.686292 10.000000 -2.000000 7.313708 -2.000000 4.000000 c
|
||||||
|
2.000000 4.000000 l
|
||||||
|
h
|
||||||
|
4.000000 6.000000 m
|
||||||
|
5.104569 6.000000 6.000000 5.104569 6.000000 4.000000 c
|
||||||
|
10.000000 4.000000 l
|
||||||
|
10.000000 7.313708 7.313708 10.000000 4.000000 10.000000 c
|
||||||
|
4.000000 6.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
4505
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
<< /Type /XObject
|
||||||
|
/Length 4 0 R
|
||||||
|
/Group << /Type /Group
|
||||||
|
/S /Transparency
|
||||||
|
>>
|
||||||
|
/Subtype /Form
|
||||||
|
/Resources << >>
|
||||||
|
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 18.799999 m
|
||||||
|
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||||
|
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||||
|
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||||
|
18.799999 30.000000 l
|
||||||
|
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||||
|
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||||
|
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||||
|
30.000000 11.200001 l
|
||||||
|
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||||
|
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||||
|
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||||
|
11.200000 0.000000 l
|
||||||
|
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||||
|
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||||
|
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||||
|
0.000000 18.799999 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
944
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /XObject << /X1 1 0 R >>
|
||||||
|
/ExtGState << /E1 << /SMask << /Type /Mask
|
||||||
|
/G 3 0 R
|
||||||
|
/S /Alpha
|
||||||
|
>>
|
||||||
|
/Type /ExtGState
|
||||||
|
>> >>
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Length 7 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
/E1 gs
|
||||||
|
/X1 Do
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
7 0 obj
|
||||||
|
46
|
||||||
|
endobj
|
||||||
|
|
||||||
|
8 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
/Resources 5 0 R
|
||||||
|
/Contents 6 0 R
|
||||||
|
/Parent 9 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
9 0 obj
|
||||||
|
<< /Kids [ 8 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
10 0 obj
|
||||||
|
<< /Pages 9 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 11
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000004763 00000 n
|
||||||
|
0000004786 00000 n
|
||||||
|
0000005978 00000 n
|
||||||
|
0000006000 00000 n
|
||||||
|
0000006298 00000 n
|
||||||
|
0000006400 00000 n
|
||||||
|
0000006421 00000 n
|
||||||
|
0000006594 00000 n
|
||||||
|
0000006668 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 10 0 R
|
||||||
|
/Size 11
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
6728
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Message/Subscriber.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Message/Subscriber.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "person_6.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
78
submodules/TelegramUI/Images.xcassets/Chat/Message/Subscriber.imageset/person_6.pdf
vendored
Normal file
78
submodules/TelegramUI/Images.xcassets/Chat/Message/Subscriber.imageset/person_6.pdf
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.018066 0.500000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
2.980786 3.972965 m
|
||||||
|
3.816679 3.972965 4.494304 4.650590 4.494304 5.486483 c
|
||||||
|
4.494304 6.322375 3.816679 7.000000 2.980786 7.000000 c
|
||||||
|
2.144894 7.000000 1.467269 6.322375 1.467269 5.486483 c
|
||||||
|
1.467269 4.650590 2.144894 3.972965 2.980786 3.972965 c
|
||||||
|
h
|
||||||
|
5.734580 1.858224 m
|
||||||
|
5.255256 2.484169 4.423840 3.027039 2.981694 3.027039 c
|
||||||
|
1.539547 3.027039 0.708129 2.484169 0.228806 1.858224 c
|
||||||
|
-0.442749 0.981247 0.471706 0.000003 1.576275 0.000003 c
|
||||||
|
4.387107 0.000003 l
|
||||||
|
5.491676 0.000003 6.406134 0.981247 5.734580 1.858224 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
639
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 6.000000 8.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000000729 00000 n
|
||||||
|
0000000751 00000 n
|
||||||
|
0000000922 00000 n
|
||||||
|
0000000996 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1055
|
||||||
|
%%EOF
|
15
submodules/TelegramUI/Images.xcassets/Chat/Message/TranscriptionLocked.imageset/Contents.json
vendored
Normal file
15
submodules/TelegramUI/Images.xcassets/Chat/Message/TranscriptionLocked.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "lockedaudiototext.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"template-rendering-intent" : "template"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 3.834961 10.247070 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
14.784782 9.993996 m
|
||||||
|
14.685381 10.249602 14.439255 10.417969 14.165000 10.417969 c
|
||||||
|
13.890745 10.417969 13.644619 10.249602 13.545217 9.993996 c
|
||||||
|
10.045217 0.993996 l
|
||||||
|
9.912102 0.651699 10.081676 0.266301 10.423973 0.133185 c
|
||||||
|
10.766270 0.000071 11.151668 0.169645 11.284783 0.511942 c
|
||||||
|
12.286572 3.087969 l
|
||||||
|
15.680867 3.087969 l
|
||||||
|
15.758190 3.902153 16.114431 4.635052 16.652981 5.190056 c
|
||||||
|
16.534782 5.493996 l
|
||||||
|
14.784782 9.993996 l
|
||||||
|
h
|
||||||
|
15.526207 4.417969 m
|
||||||
|
12.803794 4.417969 l
|
||||||
|
14.165000 7.918214 l
|
||||||
|
15.295218 5.011942 l
|
||||||
|
15.526207 4.417969 l
|
||||||
|
h
|
||||||
|
3.694774 8.723195 m
|
||||||
|
3.954473 8.982893 4.375527 8.982893 4.635226 8.723195 c
|
||||||
|
8.135226 5.223195 l
|
||||||
|
8.394924 4.963496 8.394924 4.542441 8.135226 4.282743 c
|
||||||
|
4.635226 0.782743 l
|
||||||
|
4.375527 0.523045 3.954473 0.523045 3.694774 0.782743 c
|
||||||
|
3.435075 1.042441 3.435075 1.463496 3.694774 1.723194 c
|
||||||
|
6.059548 4.087969 l
|
||||||
|
0.665000 4.087969 l
|
||||||
|
0.297731 4.087969 0.000000 4.385699 0.000000 4.752969 c
|
||||||
|
0.000000 5.120238 0.297731 5.417969 0.665000 5.417969 c
|
||||||
|
6.059548 5.417969 l
|
||||||
|
3.694774 7.782743 l
|
||||||
|
3.435075 8.042441 3.435075 8.463496 3.694774 8.723195 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 21.000000 7.669922 cm
|
||||||
|
0.898039 0.949020 1.000000 scn
|
||||||
|
3.335000 1.330078 m
|
||||||
|
3.335000 0.962809 3.632731 0.665078 4.000000 0.665078 c
|
||||||
|
4.367270 0.665078 4.665000 0.962809 4.665000 1.330078 c
|
||||||
|
3.335000 1.330078 l
|
||||||
|
h
|
||||||
|
-0.665000 1.330078 m
|
||||||
|
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||||
|
0.367269 0.665078 0.665000 0.962809 0.665000 1.330078 c
|
||||||
|
-0.665000 1.330078 l
|
||||||
|
h
|
||||||
|
3.335000 5.330078 m
|
||||||
|
3.335000 1.330078 l
|
||||||
|
4.665000 1.330078 l
|
||||||
|
4.665000 5.330078 l
|
||||||
|
3.335000 5.330078 l
|
||||||
|
h
|
||||||
|
0.665000 1.330078 m
|
||||||
|
0.665000 5.330078 l
|
||||||
|
-0.665000 5.330078 l
|
||||||
|
-0.665000 1.330078 l
|
||||||
|
0.665000 1.330078 l
|
||||||
|
h
|
||||||
|
2.000000 6.665078 m
|
||||||
|
2.737300 6.665078 3.335000 6.067378 3.335000 5.330078 c
|
||||||
|
4.665000 5.330078 l
|
||||||
|
4.665000 6.801917 3.471839 7.995078 2.000000 7.995078 c
|
||||||
|
2.000000 6.665078 l
|
||||||
|
h
|
||||||
|
2.000000 7.995078 m
|
||||||
|
0.528161 7.995078 -0.665000 6.801917 -0.665000 5.330078 c
|
||||||
|
0.665000 5.330078 l
|
||||||
|
0.665000 6.067378 1.262700 6.665078 2.000000 6.665078 c
|
||||||
|
2.000000 7.995078 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 21.000000 7.669922 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
3.335000 1.330078 m
|
||||||
|
3.335000 0.962809 3.632731 0.665078 4.000000 0.665078 c
|
||||||
|
4.367270 0.665078 4.665000 0.962809 4.665000 1.330078 c
|
||||||
|
3.335000 1.330078 l
|
||||||
|
h
|
||||||
|
-0.665000 1.330078 m
|
||||||
|
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||||
|
0.367269 0.665078 0.665000 0.962809 0.665000 1.330078 c
|
||||||
|
-0.665000 1.330078 l
|
||||||
|
h
|
||||||
|
3.335000 5.330078 m
|
||||||
|
3.335000 1.330078 l
|
||||||
|
4.665000 1.330078 l
|
||||||
|
4.665000 5.330078 l
|
||||||
|
3.335000 5.330078 l
|
||||||
|
h
|
||||||
|
0.665000 1.330078 m
|
||||||
|
0.665000 5.330078 l
|
||||||
|
-0.665000 5.330078 l
|
||||||
|
-0.665000 1.330078 l
|
||||||
|
0.665000 1.330078 l
|
||||||
|
h
|
||||||
|
2.000000 6.665078 m
|
||||||
|
2.737300 6.665078 3.335000 6.067378 3.335000 5.330078 c
|
||||||
|
4.665000 5.330078 l
|
||||||
|
4.665000 6.801917 3.471839 7.995078 2.000000 7.995078 c
|
||||||
|
2.000000 6.665078 l
|
||||||
|
h
|
||||||
|
2.000000 7.995078 m
|
||||||
|
0.528161 7.995078 -0.665000 6.801917 -0.665000 5.330078 c
|
||||||
|
0.665000 5.330078 l
|
||||||
|
0.665000 6.067378 1.262700 6.665078 2.000000 6.665078 c
|
||||||
|
2.000000 7.995078 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 19.500000 6.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 3.000000 m
|
||||||
|
0.000000 3.931883 0.000000 4.397825 0.152241 4.765367 c
|
||||||
|
0.355229 5.255423 0.744577 5.644771 1.234633 5.847759 c
|
||||||
|
1.602175 6.000000 2.068117 6.000000 3.000000 6.000000 c
|
||||||
|
4.000000 6.000000 l
|
||||||
|
4.931883 6.000000 5.397825 6.000000 5.765367 5.847759 c
|
||||||
|
6.255423 5.644771 6.644771 5.255423 6.847759 4.765367 c
|
||||||
|
7.000000 4.397825 7.000000 3.931883 7.000000 3.000000 c
|
||||||
|
7.000000 3.000000 l
|
||||||
|
7.000000 2.068117 7.000000 1.602175 6.847759 1.234633 c
|
||||||
|
6.644771 0.744577 6.255423 0.355228 5.765367 0.152241 c
|
||||||
|
5.397825 0.000000 4.931883 0.000000 4.000000 0.000000 c
|
||||||
|
3.000000 0.000000 l
|
||||||
|
2.068117 0.000000 1.602175 0.000000 1.234633 0.152241 c
|
||||||
|
0.744577 0.355228 0.355229 0.744577 0.152241 1.234633 c
|
||||||
|
0.000000 1.602175 0.000000 2.068117 0.000000 3.000000 c
|
||||||
|
0.000000 3.000000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
3999
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000004089 00000 n
|
||||||
|
0000004112 00000 n
|
||||||
|
0000004285 00000 n
|
||||||
|
0000004359 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
4418
|
||||||
|
%%EOF
|
@ -3694,7 +3694,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let strongSelf = self, let (id, statsDatacenterId) = messageIdAndStatsDatacenterId, let statsDatacenterId = statsDatacenterId else {
|
guard let strongSelf = self, let (id, statsDatacenterId) = messageIdAndStatsDatacenterId, let statsDatacenterId = statsDatacenterId else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(messageStatsController(context: context, messageId: id, statsDatacenterId: statsDatacenterId))
|
strongSelf.push(messageStatsController(context: context, subject: .message(id: id), statsDatacenterId: statsDatacenterId))
|
||||||
})
|
})
|
||||||
}, delay: true)
|
}, delay: true)
|
||||||
}, editMessageMedia: { [weak self] messageId, draw in
|
}, editMessageMedia: { [weak self] messageId, draw in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user