From ff09220634e5300cfbd99bc9125c07482387bf6c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Apr 2024 21:04:14 +0400 Subject: [PATCH] Recent Actions improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + .../BUILD | 4 +- .../Sources/CounterControllerTitleView.swift} | 6 +- submodules/SettingsUI/BUILD | 2 +- .../Themes/ThemePreviewController.swift | 10 +- submodules/TelegramUI/BUILD | 2 +- .../Sources/ChatMessageBubbleItemNode.swift | 2 +- .../Sources/ChatMessageThreadInfoNode.swift | 8 +- .../Chat/ChatRecentActionsController/BUILD | 1 + .../Sources/ChatRecentActionsController.swift | 48 ++++---- .../ChatRecentActionsControllerNode.swift | 83 +++++++++++-- .../Sources/ChatRecentActionsEmptyNode.swift | 33 ++++-- .../ChatRecentActionsHistoryTransition.swift | 40 ++++++- .../Settings/WallpaperGalleryScreen/BUILD | 2 +- .../Sources/WallpaperGalleryController.swift | 6 +- .../Chat/Recent Actions/Contents.json | 9 ++ .../Info.imageset/Contents.json | 12 ++ .../Info.imageset/question.circle.pdf | 99 ++++++++++++++++ .../Placeholder.imageset/Contents.json | 12 ++ .../Placeholder.imageset/recentactions.pdf | 110 ++++++++++++++++++ .../ContactMultiselectionController.swift | 24 ++-- submodules/WebUI/BUILD | 2 +- .../WebUI/Sources/WebAppController.swift | 8 +- 23 files changed, 440 insertions(+), 85 deletions(-) rename submodules/{CounterContollerTitleView => CounterControllerTitleView}/BUILD (83%) rename submodules/{CounterContollerTitleView/Sources/CounterContollerTitleView.swift => CounterControllerTitleView/Sources/CounterControllerTitleView.swift} (95%) create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a960050c2a..f1aac17973 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -12089,3 +12089,5 @@ Sorry for the inconvenience."; "Map.SharingLocation" = "Sharing Location..."; "Channel.AdminLog.Settings" = "Settings"; + +"Conversation.ContextMenuBanFull" = "Ban"; diff --git a/submodules/CounterContollerTitleView/BUILD b/submodules/CounterControllerTitleView/BUILD similarity index 83% rename from submodules/CounterContollerTitleView/BUILD rename to submodules/CounterControllerTitleView/BUILD index 7ad134d009..f63f0315bb 100644 --- a/submodules/CounterContollerTitleView/BUILD +++ b/submodules/CounterControllerTitleView/BUILD @@ -1,8 +1,8 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") swift_library( - name = "CounterContollerTitleView", - module_name = "CounterContollerTitleView", + name = "CounterControllerTitleView", + module_name = "CounterControllerTitleView", srcs = glob([ "Sources/**/*.swift", ]), diff --git a/submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift similarity index 95% rename from submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift rename to submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift index 17c9e99ac0..42d3b93faa 100644 --- a/submodules/CounterContollerTitleView/Sources/CounterContollerTitleView.swift +++ b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift @@ -4,7 +4,7 @@ import Display import AsyncDisplayKit import TelegramPresentationData -public struct CounterContollerTitle: Equatable { +public struct CounterControllerTitle: Equatable { public var title: String public var counter: String @@ -14,11 +14,11 @@ public struct CounterContollerTitle: Equatable { } } -public final class CounterContollerTitleView: UIView { +public final class CounterControllerTitleView: UIView { private let titleNode: ImmediateTextNode private let subtitleNode: ImmediateTextNode - public var title: CounterContollerTitle = CounterContollerTitle(title: "", counter: "") { + public var title: CounterControllerTitle = CounterControllerTitle(title: "", counter: "") { didSet { if self.title != oldValue { self.update() diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index 228236a2bc..347920fa64 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -77,7 +77,7 @@ swift_library( "//submodules/AuthorizationUI:AuthorizationUI", "//submodules/InstantPageUI:InstantPageUI", "//submodules/CheckNode:CheckNode", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/GridMessageSelectionNode:GridMessageSelectionNode", "//submodules/InstantPageCache:InstantPageCache", "//submodules/AppBundle:AppBundle", diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift index 102f847329..d000c3da2b 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift @@ -9,7 +9,7 @@ import TelegramPresentationData import TelegramUIPreferences import AccountContext import ShareController -import CounterContollerTitleView +import CounterControllerTitleView import WallpaperResources import OverlayStatusController import AppBundle @@ -139,8 +139,8 @@ public final class ThemePreviewController: ViewController { isPreview = true } - let titleView = CounterContollerTitleView(theme: self.previewTheme) - titleView.title = CounterContollerTitle(title: themeName, counter: hasInstallsCount ? " " : "") + let titleView = CounterControllerTitleView(theme: self.previewTheme) + titleView.title = CounterControllerTitle(title: themeName, counter: hasInstallsCount ? " " : "") self.navigationItem.titleView = titleView self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) @@ -154,8 +154,8 @@ public final class ThemePreviewController: ViewController { self.disposable = (combineLatest(self.theme.get(), self.presentationTheme.get()) |> deliverOnMainQueue).start(next: { [weak self] theme, presentationTheme in if let strongSelf = self, let theme = theme { - let titleView = CounterContollerTitleView(theme: strongSelf.previewTheme) - titleView.title = CounterContollerTitle(title: themeName, counter: hasInstallsCount ? strongSelf.presentationData.strings.Theme_UsersCount(max(1, theme.installCount ?? 0)) : "") + let titleView = CounterControllerTitleView(theme: strongSelf.previewTheme) + titleView.title = CounterControllerTitle(title: themeName, counter: hasInstallsCount ? strongSelf.presentationData.strings.Theme_UsersCount(max(1, theme.installCount ?? 0)) : "") strongSelf.navigationItem.titleView = titleView strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationTheme: presentationTheme, presentationStrings: strongSelf.presentationData.strings)) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 9a7c974d27..867c3ef62c 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -201,7 +201,7 @@ swift_library( "//submodules/QrCode:QrCode", "//submodules/WallpaperResources:WallpaperResources", "//submodules/AuthorizationUI:AuthorizationUI", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/GridMessageSelectionNode:GridMessageSelectionNode", "//submodules/InstantPageCache:InstantPageCache", "//submodules/PersistentStringHash:PersistentStringHash", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 6f81354381..ea196dfb69 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -2366,7 +2366,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI } var hasReply = replyMessage != nil || replyForward != nil || replyStory != nil - if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil { + if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1 || item.associatedData.isRecentActions), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil { if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId { hasReply = false } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift index 1fab74cb24..f8f4523fd8 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode/Sources/ChatMessageThreadInfoNode.swift @@ -481,8 +481,12 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { } let titleTopicIconContent: EmojiStatusComponent.Content + var containerSize: CGSize = CGSize(width: 22.0, height: 22.0) + var iconX: CGFloat = 0.0 if arguments.threadId == 1 { titleTopicIconContent = .image(image: generalThreadIcon) + containerSize = CGSize(width: 18.0, height: 18.0) + iconX = 3.0 } else if let fileId = topicIconId, fileId != 0 { titleTopicIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 36.0, height: 36.0), placeholderColor: arguments.presentationData.theme.theme.list.mediaPlaceholderColor, themeColor: arguments.presentationData.theme.theme.list.itemAccentColor, loopMode: .count(1)) } else { @@ -504,7 +508,7 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { transition: .immediate, component: AnyComponent(titleTopicIconComponent), environment: {}, - containerSize: CGSize(width: 22.0, height: 22.0) + containerSize: containerSize ) let iconY: CGFloat @@ -514,7 +518,7 @@ public class ChatMessageThreadInfoNode: ASDisplayNode { iconY = 0.0 } - titleTopicIconView.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top + iconY), size: iconSize) + titleTopicIconView.frame = CGRect(origin: CGPoint(x: insets.left + iconX, y: insets.top + iconY), size: iconSize) } let textFrame = CGRect(origin: CGPoint(x: iconSize.width + 2.0 + insets.left, y: insets.top), size: textLayout.size) diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD index 6869a58873..740cd3852d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/BUILD @@ -48,6 +48,7 @@ swift_library( "//submodules/UndoUI", "//submodules/WallpaperBackgroundNode", "//submodules/TextFormat", + "//submodules/CounterControllerTitleView" ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift index 47f0d60b62..5cbdfd5789 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift @@ -11,6 +11,7 @@ import AlertUI import PresentationDataUtils import ChatPresentationInterfaceState import ChatNavigationButton +import CounterControllerTitleView public final class ChatRecentActionsController: TelegramBaseController { private var controllerNode: ChatRecentActionsControllerNode { @@ -28,10 +29,10 @@ public final class ChatRecentActionsController: TelegramBaseController { private var presentationDataDisposable: Disposable? private var didSetPresentationData = false - private var interaction: ChatRecentActionsInteraction! private var panelInteraction: ChatPanelInterfaceInteraction! - private let titleView: ChatRecentActionsTitleView + private let titleView: CounterControllerTitleView + private var rightBarButton: ChatNavigationButton? public init(context: AccountContext, peer: Peer, adminPeerId: PeerId?) { self.context = context @@ -40,7 +41,7 @@ public final class ChatRecentActionsController: TelegramBaseController { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - self.titleView = ChatRecentActionsTitleView(color: self.presentationData.theme.rootController.navigationBar.primaryTextColor) + self.titleView = CounterControllerTitleView(theme: self.presentationData.theme) super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none, groupCallPanelSource: .none) @@ -48,18 +49,6 @@ public final class ChatRecentActionsController: TelegramBaseController { self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style - self.interaction = ChatRecentActionsInteraction(displayInfoAlert: { [weak self] in - if let strongSelf = self { - let text: String - if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelChannelAlertText - } else { - text = strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelAlertText - } - self?.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: strongSelf.presentationData.strings.Channel_AdminLog_InfoPanelAlertTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - } - }) - self.panelInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in }, setupEditMessage: { _, _ in }, beginMessageSelection: { _, _ in @@ -181,13 +170,10 @@ public final class ChatRecentActionsController: TelegramBaseController { self.navigationItem.titleView = self.titleView - let rightButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) - self.navigationItem.setRightBarButton(rightButton.buttonItem, animated: false) + let rightBarButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) + self.rightBarButton = rightBarButton - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleAllEvents - self.titleView.pressed = { [weak self] in - self?.openFilterSetup() - } + self.titleView.title = CounterControllerTitle(title: EnginePeer(peer).compactDisplayTitle, counter: self.presentationData.strings.Channel_AdminLog_TitleAllEvents) let themeEmoticon = self.context.account.postbox.peerView(id: peer.id) |> map { view -> String? in @@ -238,7 +224,7 @@ public final class ChatRecentActionsController: TelegramBaseController { } private func updateThemeAndStrings() { - self.titleView.color = self.presentationData.theme.rootController.navigationBar.primaryTextColor + self.titleView.theme = self.presentationData.theme self.updateTitle() let rightButton = ChatNavigationButton(action: .search(hasTags: false), buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.activateSearch))) @@ -251,14 +237,19 @@ public final class ChatRecentActionsController: TelegramBaseController { } override public func loadDisplayNode() { - self.displayNode = ChatRecentActionsControllerNode(context: self.context, controller: self, peer: self.peer, presentationData: self.presentationData, interaction: self.interaction, pushController: { [weak self] c in + self.displayNode = ChatRecentActionsControllerNode(context: self.context, controller: self, peer: self.peer, presentationData: self.presentationData, pushController: { [weak self] c in (self?.navigationController as? NavigationController)?.pushViewController(c) }, presentController: { [weak self] c, t, a in self?.present(c, in: t, with: a, blockInteraction: true) }, getNavigationController: { [weak self] in return self?.navigationController as? NavigationController }) - + self.controllerNode.isEmptyUpdated = { [weak self] isEmpty in + guard let self, let rightBarButton = self.rightBarButton else { + return + } + self.navigationItem.setRightBarButton(isEmpty ? nil : rightBarButton.buttonItem, animated: true) + } if let adminPeerId = self.initialAdminPeerId { self.controllerNode.updateFilter(events: .all, adminPeerIds: [adminPeerId]) self.updateTitle() @@ -300,7 +291,7 @@ public final class ChatRecentActionsController: TelegramBaseController { self.updateTitle() } - private func openFilterSetup() { + func openFilterSetup() { self.present(channelRecentActionsFilterController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: self.peer, events: self.controllerNode.filter.events, adminPeerIds: self.controllerNode.filter.adminPeerIds, apply: { [weak self] events, adminPeerIds in self?.controllerNode.updateFilter(events: events, adminPeerIds: adminPeerIds) self?.updateTitle() @@ -308,10 +299,13 @@ public final class ChatRecentActionsController: TelegramBaseController { } private func updateTitle() { + let title = EnginePeer(self.peer).compactDisplayTitle + let subtitle: String if self.controllerNode.filter.isEmpty { - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleAllEvents + subtitle = self.presentationData.strings.Channel_AdminLog_TitleAllEvents } else { - self.titleView.title = self.presentationData.strings.Channel_AdminLog_TitleSelectedEvents + subtitle = self.presentationData.strings.Channel_AdminLog_TitleSelectedEvents } + self.titleView.title = CounterControllerTitle(title: title, counter: subtitle) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index 25f00a7482..1db3236edd 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -49,8 +49,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private let pushController: (ViewController) -> Void private let presentController: (ViewController, PresentationContextType, Any?) -> Void private let getNavigationController: () -> NavigationController? + var isEmptyUpdated: (Bool) -> Void = { _ in } - private let interaction: ChatRecentActionsInteraction private var controllerInteraction: ChatControllerInteraction! private let galleryHiddenMesageAndMediaDisposable = MetaDisposable() @@ -68,6 +68,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private let panelBackgroundNode: NavigationBackgroundNode private let panelSeparatorNode: ASDisplayNode private let panelButtonNode: HighlightableButtonNode + private let panelInfoButtonNode: HighlightableButtonNode fileprivate let listNode: ListView private let loadingNode: ChatLoadingNode @@ -99,12 +100,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { private weak var controller: ChatRecentActionsController? - init(context: AccountContext, controller: ChatRecentActionsController, peer: Peer, presentationData: PresentationData, interaction: ChatRecentActionsInteraction, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, PresentationContextType, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) { + init(context: AccountContext, controller: ChatRecentActionsController, peer: Peer, presentationData: PresentationData, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, PresentationContextType, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) { self.context = context self.controller = controller self.peer = peer self.presentationData = presentationData - self.interaction = interaction self.pushController = pushController self.presentController = presentController self.getNavigationController = getNavigationController @@ -118,7 +118,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.panelSeparatorNode = ASDisplayNode() self.panelSeparatorNode.backgroundColor = self.presentationData.theme.chat.inputPanel.panelSeparatorColor self.panelButtonNode = HighlightableButtonNode() - self.panelButtonNode.setTitle(self.presentationData.strings.Channel_AdminLog_InfoPanelTitle, with: Font.regular(17.0), with: self.presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelButtonNode.setTitle(self.presentationData.strings.Channel_AdminLog_Settings, with: Font.regular(17.0), with: self.presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelInfoButtonNode = HighlightableButtonNode() self.listNode = ListView() self.listNode.dynamicBounceEnabled = false @@ -145,8 +146,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.addSubnode(self.panelBackgroundNode) self.addSubnode(self.panelSeparatorNode) self.addSubnode(self.panelButtonNode) + self.addSubnode(self.panelInfoButtonNode) - self.panelButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside) + self.panelButtonNode.addTarget(self, action: #selector(self.settingsButtonPressed), forControlEvents: .touchUpInside) + self.panelInfoButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside) let (adminsDisposable, _) = self.context.peerChannelMemberCategoriesContextsManager.admins(engine: self.context.engine, postbox: self.context.account.postbox, network: self.context.account.network, accountPeerId: context.account.peerId, peerId: self.peer.id, searchQuery: nil, updated: { [weak self] state in self?.adminsState = state @@ -275,7 +278,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, activateMessagePinch: { _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _, _ in }, navigateToMessageStandalone: { _ in - }, navigateToThreadMessage: { _, _, _ in + }, navigateToThreadMessage: { [weak self] peerId, threadId, _ in + if let context = self?.context, let navigationController = self?.getNavigationController() { + let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .always).startStandalone() + } }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _, _ in }, openUrl: { [weak self] url in self?.openUrl(url.url) }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in @@ -674,7 +680,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.panelBackgroundNode.updateColor(color: presentationData.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate) self.panelSeparatorNode.backgroundColor = presentationData.theme.chat.inputPanel.panelSeparatorColor - self.panelButtonNode.setTitle(presentationData.strings.Channel_AdminLog_InfoPanelTitle, with: Font.regular(17.0), with: presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelButtonNode.setTitle(presentationData.strings.Channel_AdminLog_Settings, with: Font.regular(17.0), with: presentationData.theme.chat.inputPanel.panelControlAccentColor, for: []) + self.panelInfoButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Recent Actions/Info"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: .normal) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { @@ -695,7 +702,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { transition.updateFrame(node: self.panelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight))) self.panelBackgroundNode.update(size: self.panelBackgroundNode.bounds.size, transition: transition) transition.updateFrame(node: self.panelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: intrinsicPanelHeight))) + + let infoButtonSize = CGSize(width: 56.0, height: intrinsicPanelHeight) + transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: insets.left + infoButtonSize.width, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width - insets.left - insets.right - infoButtonSize.width * 2.0, height: intrinsicPanelHeight))) + + transition.updateFrame(node: self.panelInfoButtonNode, frame: CGRect(origin: CGPoint(x: layout.size.width - insets.right - infoButtonSize.width, y: layout.size.height - panelHeight), size: infoButtonSize)) self.visibleAreaInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: panelHeight, right: 0.0) @@ -788,6 +799,12 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { strongSelf.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } strongSelf.isLoading = isLoading + + var isEmpty = false + if strongSelf.filter.isEmpty && (transition.isEmpty || isLoading) { + isEmpty = true + } + strongSelf.isEmptyUpdated(isEmpty) } }) } else { @@ -796,8 +813,22 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { } } + @objc func settingsButtonPressed() { + self.controller?.openFilterSetup() + } + @objc func infoButtonPressed() { - self.interaction.displayInfoAlert() + guard let controller = self.controller else { + return + } + let text: String + if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info { + text = self.presentationData.strings.Channel_AdminLog_InfoPanelChannelAlertText + } else { + text = self.presentationData.strings.Channel_AdminLog_InfoPanelAlertText + } + controller.present(textAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, title: self.presentationData.strings.Channel_AdminLog_InfoPanelAlertTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } func updateSearchQuery(_ query: String) { @@ -936,6 +967,40 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { } })) ) + actions.append( + .action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuBanFull, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Ban"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] _, f in + if let strongSelf = self { + f(.default) + strongSelf.banDisposables.set((strongSelf.context.engine.peers.fetchChannelParticipant(peerId: strongSelf.peer.id, participantId: author.id) + |> deliverOnMainQueue).startStrict(next: { participant in + if let strongSelf = self { + let initialUserBannedRights = participant?.banInfo?.rights + strongSelf.banDisposables.set(strongSelf.context.engine.peers.removePeerMember(peerId: strongSelf.peer.id, memberId: author.id).startStandalone(), forKey: author.id) + + strongSelf.presentController(UndoOverlayController( + presentationData: strongSelf.presentationData, + content: .actionSucceeded(title: nil, text: "**\(EnginePeer(author).compactDisplayTitle)** was banned.", cancel: strongSelf.presentationData.strings.Undo_Undo, destructive: false), + elevatedLayout: false, + action: { [weak self] action in + guard let self else { + return true + } + switch action { + case .commit: + break + case .undo: + let _ = self.context.engine.peers.updateChannelMemberBannedRights(peerId: self.peer.id, memberId: author.id, rights: initialUserBannedRights).startStandalone() + default: + break + } + return true + } + ), .current, nil) + } + }), forKey: author.id) + } + })) + ) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift index 0b2e4048a3..7f61a30adc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsEmptyNode.swift @@ -7,14 +7,15 @@ import TelegramPresentationData import WallpaperBackgroundNode import ChatPresentationInterfaceState -private let titleFont = Font.medium(16.0) -private let textFont = Font.regular(15.0) +private let titleFont = Font.semibold(15.0) +private let textFont = Font.regular(13.0) public final class ChatRecentActionsEmptyNode: ASDisplayNode { private var theme: PresentationTheme private var chatWallpaper: TelegramWallpaper private let backgroundNode: NavigationBackgroundNode + private let iconNode: ASImageNode private let titleNode: TextNode private let textNode: TextNode @@ -34,6 +35,9 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.backgroundNode = NavigationBackgroundNode(color: .clear) + self.iconNode = ASImageNode() + self.iconNode.displaysAsynchronously = false + self.titleNode = TextNode() self.titleNode.isUserInteractionEnabled = false @@ -45,6 +49,7 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.allowsGroupOpacity = true self.addSubnode(self.backgroundNode) + self.addSubnode(self.iconNode) self.addSubnode(self.titleNode) self.addSubnode(self.textNode) } @@ -63,14 +68,15 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { self.wallpaperBackgroundNode = backgroundNode self.layoutParams = (size, presentationData) + let themeUpdated = self.theme !== presentationData.theme.theme self.theme = presentationData.theme.theme self.chatWallpaper = presentationData.theme.wallpaper self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate) - let insets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) + let insets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 25.0, right: 16.0) - let maxTextWidth = size.width - insets.left - insets.right - 18.0 * 2.0 + let maxTextWidth = min(196.0, size.width - insets.left - insets.right - 18.0 * 2.0) let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTextLayout = TextNode.asyncLayout(self.textNode) @@ -78,17 +84,28 @@ public final class ChatRecentActionsEmptyNode: ASDisplayNode { let serviceColor = serviceMessageColorComponents(theme: self.theme, wallpaper: self.chatWallpaper) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: self.title, font: titleFont, textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - let spacing: CGFloat = titleLayout.size.height.isZero ? 0.0 : 5.0 + let spacing: CGFloat = titleLayout.size.height.isZero ? 0.0 : 7.0 let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: self.text, font: textFont, textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - let contentSize = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + insets.left + insets.right, height: insets.top + insets.bottom + titleLayout.size.height + spacing + textLayout.size.height) + if themeUpdated || self.iconNode.image == nil { + self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Recent Actions/Placeholder"), color: serviceColor.primaryText) + } + let iconSize = self.iconNode.image?.size ?? .zero + + let contentSize = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + insets.left + insets.right, height: 5.0 + insets.bottom + iconSize.height - 2.0 + titleLayout.size.height + spacing + textLayout.size.height) let backgroundFrame = CGRect(origin: CGPoint(x: floor((size.width - contentSize.width) / 2.0), y: floor((size.height - contentSize.height) / 2.0)), size: contentSize) transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(14.0, self.backgroundNode.bounds.height / 2.0), transition: transition) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - titleLayout.size.width) / 2.0), y: backgroundFrame.minY + insets.top), size: titleLayout.size)) - transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - textLayout.size.width) / 2.0), y: backgroundFrame.minY + insets.top + titleLayout.size.height + spacing), size: textLayout.size)) + let iconFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - iconSize.width) / 2.0), y: backgroundFrame.minY + 5.0), size: iconSize) + transition.updateFrame(node: self.iconNode, frame: iconFrame) + let titleFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - titleLayout.size.width) / 2.0), y: iconFrame.maxY - 2.0), size: titleLayout.size) + transition.updateFrame(node: self.titleNode, frame: titleFrame) + + let textFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((contentSize.width - textLayout.size.width) / 2.0), y: titleFrame.maxY + spacing), size: textLayout.size) + transition.updateFrame(node: self.textNode, frame: textFrame) + let _ = titleApply() let _ = textApply() diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift index cfc70b0418..37a06dddc2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsHistoryTransition.swift @@ -404,6 +404,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -412,7 +415,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } else { var peers = SimpleDictionary() @@ -488,6 +494,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -496,7 +505,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil) } case let .deleteMessage(message): @@ -531,6 +543,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -549,7 +564,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let peer = self.entry.peers[self.entry.event.peerId] { peers[peer.id] = peer } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: message.id.id), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: message.id.id), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } case .participantJoin, .participantLeave: @@ -1110,6 +1128,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -1118,7 +1139,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil) } case let .linkedPeerUpdated(previous, updated): @@ -1706,6 +1730,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let attribute = attribute as? TextEntitiesMessageAttribute { attributes.append(attribute) } + if let attribute = attribute as? ReplyMessageAttribute { + attributes.append(attribute) + } } for attribute in attributes { for peerId in attribute.associatedPeerIds { @@ -1714,7 +1741,10 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } } - let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) + if let peer = self.entry.peers[message.id.peerId] { + peers[peer.id] = peer + } + let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:]) return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } case let .createTopic(info): diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD index 882bfd1377..45b7b88b4e 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/BUILD @@ -28,7 +28,7 @@ swift_library( "//submodules/MergeLists", "//submodules/ShareController", "//submodules/GalleryUI", - "//submodules/CounterContollerTitleView", + "//submodules/CounterControllerTitleView", "//submodules/LegacyMediaPickerUI", "//submodules/TelegramUI/Components/Settings/SettingsThemeWallpaperNode", "//submodules/TelegramUI/Components/PremiumLockButtonSubtitleComponent", diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift index c306b30e67..25faa1b007 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift @@ -14,7 +14,7 @@ import AccountContext import ShareController import GalleryUI import HexColor -import CounterContollerTitleView +import CounterControllerTitleView import UndoUI import LegacyComponents import LegacyMediaPickerUI @@ -350,8 +350,8 @@ public class WallpaperGalleryController: ViewController { self.centralItemAttributesDisposable.add(self.centralItemSubtitle.get().start(next: { [weak self] subtitle in if let strongSelf = self { if let subtitle = subtitle { - let titleView = CounterContollerTitleView(theme: strongSelf.presentationData.theme) - titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.WallpaperPreview_Title, counter: subtitle) + let titleView = CounterControllerTitleView(theme: strongSelf.presentationData.theme) + titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.WallpaperPreview_Title, counter: subtitle) strongSelf.navigationItem.titleView = titleView strongSelf.title = nil } else { diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json new file mode 100644 index 0000000000..6e965652df --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json new file mode 100644 index 0000000000..cb1f2a6fcb --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "question.circle.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf new file mode 100644 index 0000000000..071d47854f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Info.imageset/question.circle.pdf @@ -0,0 +1,99 @@ +%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 4.334961 4.334999 cm +0.000000 0.000000 0.000000 scn +10.665000 20.000002 m +5.509422 20.000002 1.330000 15.820580 1.330000 10.665002 c +1.330000 5.509424 5.509422 1.330002 10.665000 1.330002 c +15.820578 1.330002 20.000000 5.509424 20.000000 10.665002 c +20.000000 15.820580 15.820578 20.000002 10.665000 20.000002 c +h +0.000000 10.665002 m +0.000000 16.555119 4.774883 21.330002 10.665000 21.330002 c +16.555117 21.330002 21.330002 16.555119 21.330002 10.665002 c +21.330002 4.774885 16.555117 0.000000 10.665000 0.000000 c +4.774883 0.000000 0.000000 4.774885 0.000000 10.665002 c +h +10.665000 15.138485 m +9.306379 15.138485 8.205000 14.037106 8.205000 12.678485 c +8.205000 12.311215 7.907269 12.013485 7.540000 12.013485 c +7.172730 12.013485 6.875000 12.311215 6.875000 12.678485 c +6.875000 14.771645 8.571840 16.468485 10.665000 16.468485 c +12.758160 16.468485 14.455000 14.771645 14.455000 12.678485 c +14.455000 11.036498 13.411167 9.640008 11.953011 9.113155 c +11.520578 8.956911 11.330000 8.669144 11.330000 8.470152 c +11.330000 7.990985 l +11.330000 7.623715 11.032269 7.325985 10.665000 7.325985 c +10.297730 7.325985 10.000000 7.623715 10.000000 7.990985 c +10.000000 8.470152 l +10.000000 9.467776 10.808081 10.113627 11.501059 10.364010 c +12.449083 10.706545 13.125000 11.614429 13.125000 12.678485 c +13.125000 14.037106 12.023621 15.138485 10.665000 15.138485 c +h +10.664997 4.006662 m +11.240294 4.006662 11.706664 4.473032 11.706664 5.048328 c +11.706664 5.623627 11.240294 6.089996 10.664997 6.089996 c +10.089701 6.089996 9.623331 5.623627 9.623331 5.048328 c +9.623331 4.473032 10.089701 4.006662 10.664997 4.006662 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1692 +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 +0000001782 00000 n +0000001805 00000 n +0000001978 00000 n +0000002052 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2111 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json new file mode 100644 index 0000000000..36e91193f0 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "recentactions.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf new file mode 100644 index 0000000000..d4a44d77bf --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Recent Actions/Placeholder.imageset/recentactions.pdf @@ -0,0 +1,110 @@ +%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 23.500000 18.363636 cm +0.000000 0.000000 0.000000 scn +36.636364 54.363636 m +35.330963 54.363636 34.306767 55.443432 33.939365 56.696064 c +32.932384 60.129303 29.758968 62.636364 26.000000 62.636364 c +22.241032 62.636364 19.067616 60.129303 18.060635 56.696064 c +17.693233 55.443432 16.669035 54.363636 15.363634 54.363636 c +7.090909 54.363636 l +3.174709 54.363636 0.000000 51.188931 0.000000 47.272728 c +0.000000 7.090908 l +0.000000 3.174709 3.174708 0.000000 7.090909 0.000000 c +44.909092 0.000000 l +48.825291 0.000000 52.000000 3.174709 52.000000 7.090908 c +52.000000 47.272728 l +52.000000 51.188927 48.825291 54.363636 44.909092 54.363636 c +36.636364 54.363636 l +h +29.545456 54.363636 m +29.545456 52.405537 27.958101 50.818184 26.000000 50.818184 c +24.041901 50.818184 22.454546 52.405537 22.454546 54.363636 c +22.454546 56.321739 24.041901 57.909092 26.000000 57.909092 c +27.958101 57.909092 29.545456 56.321739 29.545456 54.363636 c +h +14.181818 41.363636 m +12.876418 41.363636 11.818182 40.305401 11.818182 39.000000 c +11.818182 37.694599 12.876417 36.636364 14.181818 36.636364 c +37.818184 36.636364 l +39.123581 36.636364 40.181816 37.694599 40.181816 39.000000 c +40.181816 40.305401 39.123581 41.363636 37.818184 41.363636 c +14.181818 41.363636 l +h +14.181818 29.545456 m +12.876418 29.545456 11.818182 28.487217 11.818182 27.181820 c +11.818182 25.876419 12.876417 24.818180 14.181818 24.818180 c +37.818184 24.818180 l +39.123581 24.818180 40.181816 25.876419 40.181816 27.181820 c +40.181816 28.487217 39.123581 29.545456 37.818184 29.545456 c +14.181818 29.545456 l +h +11.818182 15.363636 m +11.818182 16.669041 12.876418 17.727276 14.181818 17.727276 c +28.363640 17.727276 l +29.669039 17.727276 30.727272 16.669041 30.727272 15.363636 c +30.727272 14.058239 29.669035 13.000004 28.363636 13.000004 c +14.181814 13.000004 l +12.876414 13.000004 11.818182 14.058239 11.818182 15.363636 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1962 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 100.000000 100.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 +0000002052 00000 n +0000002075 00000 n +0000002250 00000 n +0000002324 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2383 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift index 118bb3bc37..b4433818ba 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift @@ -12,7 +12,7 @@ import AccountContext import AlertUI import PresentationDataUtils import ContactListUI -import CounterContollerTitleView +import CounterControllerTitleView import EditableTokenListNode import PremiumUI import UndoUI @@ -35,7 +35,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection private let isPeerEnabled: ((EnginePeer) -> Bool)? private let attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? - private let titleView: CounterContollerTitleView + private let titleView: CounterControllerTitleView private var contactsNode: ContactMultiselectionControllerNode { return self.displayNode as! ContactMultiselectionControllerNode @@ -100,7 +100,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.limit = params.limit self.presentationData = params.updatedPresentationData?.initial ?? params.context.sharedContext.currentPresentationData.with { $0 } - self.titleView = CounterContollerTitleView(theme: self.presentationData.theme) + self.titleView = CounterControllerTitleView(theme: self.presentationData.theme) super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) @@ -250,7 +250,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection case let .chats(chatsNode): count = chatsNode.currentState.selectedPeerIds.count } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.Compose_NewGroupTitle, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.Compose_NewGroupTitle, counter: "\(count)/\(maxCount)") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -262,23 +262,23 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection if case let .contacts(contactsNode) = self.contactsNode.contentNode { count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(count)/\(maxCount)") case .requestedUsersSelection: let maxCount: Int32 = self.limit ?? 10 var count = 0 if case let .contacts(contactsNode) = self.contactsNode.contentNode { count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 } - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.RequestPeer_SelectUsers, counter: "\(count)/\(maxCount)") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.RequestPeer_SelectUsers, counter: "\(count)/\(maxCount)") case .channelCreation: - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton self.navigationItem.rightBarButtonItem = self.rightNavigationButton } case .peerSelection: - self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.PrivacyLastSeenSettings_EmpryUsersPlaceholder, counter: "") + self.titleView.title = CounterControllerTitle(title: self.presentationData.strings.PrivacyLastSeenSettings_EmpryUsersPlaceholder, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -286,7 +286,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.navigationItem.rightBarButtonItem = self.rightNavigationButton } case let .chatSelection(chatSelection): - self.titleView.title = CounterContollerTitle(title: chatSelection.title, counter: "") + self.titleView.title = CounterControllerTitle(title: chatSelection.title, counter: "") if self.rightNavigationButton == nil { let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton @@ -540,13 +540,13 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection switch strongSelf.mode { case .groupCreation: let maxCount: Int32 = strongSelf.limitsConfiguration?.maxSupergroupMemberCount ?? 5000 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") case .premiumGifting: let maxCount: Int32 = strongSelf.limit ?? 10 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") case .requestedUsersSelection: let maxCount: Int32 = strongSelf.limit ?? 10 - strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") + strongSelf.titleView.title = CounterControllerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") case .peerSelection, .channelCreation, .chatSelection: break } diff --git a/submodules/WebUI/BUILD b/submodules/WebUI/BUILD index 9fdbf7604b..ae4a135088 100644 --- a/submodules/WebUI/BUILD +++ b/submodules/WebUI/BUILD @@ -18,7 +18,7 @@ swift_library( "//submodules/PresentationDataUtils:PresentationDataUtils", "//submodules/AccountContext:AccountContext", "//submodules/AttachmentUI:AttachmentUI", - "//submodules/CounterContollerTitleView:CounterContollerTitleView", + "//submodules/CounterControllerTitleView:CounterControllerTitleView", "//submodules/HexColor:HexColor", "//submodules/PhotoResources:PhotoResources", "//submodules/ShimmerEffect:ShimmerEffect", diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 24b963a7ba..a100d6a1e6 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -9,7 +9,7 @@ import SwiftSignalKit import TelegramPresentationData import AccountContext import AttachmentUI -import CounterContollerTitleView +import CounterControllerTitleView import ContextUI import PresentationDataUtils import HexColor @@ -1703,7 +1703,7 @@ public final class WebAppController: ViewController, AttachmentContainable { return self.displayNode as! Node } - private var titleView: CounterContollerTitleView? + private var titleView: CounterControllerTitleView? fileprivate let cancelButtonNode: WebAppCancelButtonNode fileprivate let moreButtonNode: MoreButtonNode @@ -1774,8 +1774,8 @@ public final class WebAppController: ViewController, AttachmentContainable { self.navigationItem.rightBarButtonItem?.action = #selector(self.moreButtonPressed) self.navigationItem.rightBarButtonItem?.target = self - let titleView = CounterContollerTitleView(theme: self.presentationData.theme) - titleView.title = CounterContollerTitle(title: params.botName, counter: self.presentationData.strings.Bot_GenericBotStatus) + let titleView = CounterControllerTitleView(theme: self.presentationData.theme) + titleView.title = CounterControllerTitle(title: params.botName, counter: self.presentationData.strings.Bot_GenericBotStatus) self.navigationItem.titleView = titleView self.titleView = titleView