From a67ca0137d133031ad94c621e7cc14209cba9d39 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 3 Dec 2023 14:36:07 +0400 Subject: [PATCH] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 1 + .../Sources/PremiumBoostScreen.swift | 19 ++++-- .../Sources/ChannelStatsController.swift | 2 +- .../Sources/MessageStatsController.swift | 59 ++++++++++++++++++- .../Sources/StatsMessageItem.swift | 8 ++- 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a39fe843bf..55423bf607 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -5305,6 +5305,7 @@ Sorry for the inconvenience."; "Stats.LanguagesTitle" = "LANGUAGES"; "Stats.PostsTitle" = "RECENT POSTS"; +"Stats.MessageViews.NoViews" = "No views"; "Stats.MessageViews_0" = "%@ views"; "Stats.MessageViews_1" = "%@ view"; "Stats.MessageViews_2" = "%@ views"; diff --git a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift index 1fe350d102..2e2ef001cc 100644 --- a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift @@ -30,7 +30,17 @@ private struct BoostState { } return ( - .storiesChannelBoost(peer: peer, boostSubject: .stories, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount, canBoostAgain: canBoostAgain), + .storiesChannelBoost( + peer: peer, + boostSubject: .stories, + isCurrent: isCurrent, + level: currentLevel, + currentLevelBoosts: currentLevelBoosts, + nextLevelBoosts: nextLevelBoosts, + link: nil, + myBoostCount: myBoostCount, + canBoostAgain: canBoostAgain + ), boosts ) } @@ -160,9 +170,10 @@ public func PremiumBoostScreen( } let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone(completed: { - let _ = combineLatest(queue: Queue.mainQueue(), - context.engine.peers.getChannelBoostStatus(peerId: peerId), - context.engine.peers.getMyBoostStatus() + let _ = combineLatest( + queue: Queue.mainQueue(), + context.engine.peers.getChannelBoostStatus(peerId: peerId), + context.engine.peers.getMyBoostStatus() ).startStandalone(next: { boostStatus, myBoostStatus in dismissReplaceImpl?() PremiumBoostScreen(context: context, contentContext: contentContext, peerId: peerId, isCurrent: isCurrent, status: boostStatus, myBoostStatus: myBoostStatus, replacedBoosts: (Int32(slots.count), Int32(channelIds.count)), forceDark: forceDark, openPeer: openPeer, presentController: presentController, pushController: pushController, dismissed: dismissed) diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index cfeacb85ee..d67b8c8879 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -1446,7 +1446,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD return controller } -private final class ChannelStatsContextExtractedContentSource: ContextExtractedContentSource { +final class ChannelStatsContextExtractedContentSource: ContextExtractedContentSource { var keepInPlace: Bool let ignoreContentTouches: Bool = true let blurBackground: Bool = true diff --git a/submodules/StatisticsUI/Sources/MessageStatsController.swift b/submodules/StatisticsUI/Sources/MessageStatsController.swift index de7cdbc9cd..98eae65de8 100644 --- a/submodules/StatisticsUI/Sources/MessageStatsController.swift +++ b/submodules/StatisticsUI/Sources/MessageStatsController.swift @@ -16,18 +16,21 @@ import PresentationDataUtils import AppBundle import GraphUI import StoryContainerScreen +import ContextUI private final class MessageStatsControllerArguments { let context: AccountContext let loadDetailedGraph: (StatsGraph, Int64) -> Signal let openMessage: (EngineMessage.Id) -> Void let openStory: (EnginePeer.Id, EngineStoryItem, UIView) -> Void + let storyContextAction: (EnginePeer.Id, ASDisplayNode, ContextGesture?, Bool) -> Void - init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal, openMessage: @escaping (EngineMessage.Id) -> Void, openStory: @escaping (EnginePeer.Id, EngineStoryItem, UIView) -> Void) { + init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal, openMessage: @escaping (EngineMessage.Id) -> Void, openStory: @escaping (EnginePeer.Id, EngineStoryItem, UIView) -> Void, storyContextAction: @escaping (EnginePeer.Id, ASDisplayNode, ContextGesture?, Bool) -> Void) { self.context = context self.loadDetailedGraph = loadDetailedGraph self.openMessage = openMessage self.openStory = openStory + self.storyContextAction = storyContextAction } } @@ -171,6 +174,7 @@ private enum StatsEntry: ItemListNodeEntry { var forwards: Int32 = 0 var reactions: Int32 = 0 + var isStory = false let peer: Peer switch item { case let .message(message): @@ -191,6 +195,7 @@ private enum StatsEntry: ItemListNodeEntry { views = Int32(story.views?.seenCount ?? 0) forwards = Int32(story.views?.forwardCount ?? 0) reactions = Int32(story.views?.reactedCount ?? 0) + isStory = true } return StatsMessageItem(context: arguments.context, presentationData: presentationData, peer: peer, item: item, views: views, reactions: reactions, forwards: forwards, isPeer: true, sectionId: self.section, style: .blocks, action: { switch item { @@ -203,7 +208,9 @@ private enum StatsEntry: ItemListNodeEntry { if case let .story(peer, story) = item { arguments.openStory(peer.id, story, view) } - }, contextAction: nil) + }, contextAction: { node, gesture in + arguments.storyContextAction(peer.id, node, gesture, !isStory) + }) } } } @@ -305,6 +312,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD let dataSignal: Signal var loadDetailedGraphImpl: ((StatsGraph, Int64) -> Signal)? var openStoryImpl: ((EnginePeer.Id, EngineStoryItem, UIView) -> Void)? + var storyContextActionImpl: ((EnginePeer.Id, ASDisplayNode, ContextGesture?, Bool) -> Void)? var forwardsContext: StoryStatsPublicForwardsContext? let peerId: EnginePeer.Id @@ -373,6 +381,8 @@ public func messageStatsController(context: AccountContext, updatedPresentationD navigateToMessageImpl?(messageId) }, openStory: { peerId, story, view in openStoryImpl?(peerId, story, view) + }, storyContextAction: { peerId, node, gesture, isMessage in + storyContextActionImpl?(peerId, node, gesture, isMessage) }) let longLoadingSignal: Signal = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue())) @@ -534,5 +544,50 @@ public func messageStatsController(context: AccountContext, updatedPresentationD controller.push(storyContainerScreen) }) } + storyContextActionImpl = { [weak controller] peerId, sourceNode, gesture, isMessage in + guard let controller = controller, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else { + return + } + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + var items: [ContextMenuItem] = [] + + let title: String + let iconName: String + if isMessage { + title = presentationData.strings.Conversation_ViewInChannel + iconName = "Chat/Context Menu/GoToMessage" + } else { + if peerId.isGroupOrChannel { + title = presentationData.strings.ChatList_ContextOpenChannel + iconName = "Chat/Context Menu/Channels" + } else { + title = presentationData.strings.Conversation_ContextMenuOpenProfile + iconName = "Chat/Context Menu/User" + } + } + + items.append(.action(ContextMenuActionItem(text: title, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: iconName), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in + c.dismiss(completion: { + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> deliverOnMainQueue).start(next: { peer in + guard let peer = peer, let navigationController = controller?.navigationController as? NavigationController else { + return + } + if case .user = peer { + if let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: peer.largeProfileImage != nil, fromChat: false, requestsContext: nil) { + navigationController.pushViewController(controller) + } + } else { + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: nil)) + } + }) + }) + }))) + + let contextController = ContextController(presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) + controller.presentInGlobalOverlay(contextController) + } return controller } diff --git a/submodules/StatisticsUI/Sources/StatsMessageItem.swift b/submodules/StatisticsUI/Sources/StatsMessageItem.swift index 4691740299..f3a612ee4c 100644 --- a/submodules/StatisticsUI/Sources/StatsMessageItem.swift +++ b/submodules/StatisticsUI/Sources/StatsMessageItem.swift @@ -381,7 +381,13 @@ final class StatsMessageItemNode: ListViewItemNode, ItemListItemNode { } } - 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 viewsString: String + if item.views == 0 { + viewsString = item.presentationData.strings.Stats_MessageViews_NoViews + } else { + viewsString = item.presentationData.strings.Stats_MessageViews(item.views) + } + let (viewsLayout, viewsApply) = makeViewsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: viewsString, 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 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()))