diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 59f136027c..a92b38aa2f 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8182,7 +8182,7 @@ Sorry for the inconvenience."; "ChatList.SelectedTopics_any" = "%@ Topics Selected"; "ChatList.EmptyTopicsTitle" = "No topics here yet"; -"ChatList.EmptyTopicsCreate" = "Create New Topic"; +"ChatList.EmptyTopicsCreate" = "Create Topic"; "ChatList.EmptyTopicsShowAsMessages" = "Show as Messages"; "Message.AudioTranscription.SubscribeToPremium" = "Subscribe to **Telegram Premium** to convert voice to text."; @@ -8301,7 +8301,11 @@ Sorry for the inconvenience."; "Notification.OverviewTopicUnhidden" = "%1$@ unhid %2$@ %3$@"; "CreateTopic.ShowGeneral" = "Show in Topics"; -"CreateTopic.ShowGeneralInfo" = "If the 'General' topic is hidden, group members can pull down in the topic list to view it."; +"CreateTopic.ShowGeneralInfo" = "If the \"General\" topic is hidden, group members can pull down in the topic list to view it."; "Conversation.ContextMenuReportFalsePositive" = "Report False Positive"; "Group.AdminLog.AntiSpamFalsePositiveReportedText" = "Telegram moderators will review your report. Thank you!"; + +"ChatList.EmptyTopicsDescription" = "Older messages from this group have been moved to \"General\"."; + +"Stickers.EmojiPackInfoText" = "This message contains **%@** emoji."; diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index d5164abb3a..aef5bbeaea 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -776,7 +776,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: } private func openCustomMute(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, baseController: ViewController) { - let controller = ChatTimerScreen(context: context, updatedPresentationData: nil, peerId: peerId, style: .default, mode: .mute, currentTime: nil, dismissByTapOutside: true, completion: { [weak baseController] value in + let controller = ChatTimerScreen(context: context, updatedPresentationData: nil, style: .default, mode: .mute, currentTime: nil, dismissByTapOutside: true, completion: { [weak baseController] value in let presentationData = context.sharedContext.currentPresentationData.with { $0 } if value <= 0 { diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 510b89793b..5886d8c534 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1173,14 +1173,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } } - self.chatListDisplayNode.emptyListAction = { [weak self] in + self.chatListDisplayNode.emptyListAction = { [weak self] forumPeerId in guard let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController else { return } if let filter = strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter { strongSelf.push(chatListFilterPresetController(context: strongSelf.context, currentPreset: filter, updated: { _ in })) } else { - if case let .forum(peerId) = strongSelf.location { + if let peerId = forumPeerId { let context = strongSelf.context let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create) controller.navigationPresentation = .modal diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 4615477753..43aa3aa96f 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -333,68 +333,75 @@ private final class ChatListContainerItemNode: ASDisplayNode { } var needsShimmerNode = false var shimmerNodeOffset: CGFloat = 0.0 + + var needsEmptyNode = false + var hasOnlyGeneralThread = false + var isLoading = false + switch isEmptyState { - case let .empty(isLoading, hasArchiveInfo): + case let .empty(isLoadingValue, hasArchiveInfo): if hasArchiveInfo { shimmerNodeOffset = 253.0 } - if isLoading { + if isLoadingValue { needsShimmerNode = true - - if let emptyNode = strongSelf.emptyNode { - strongSelf.emptyNode = nil - transition.updateAlpha(node: emptyNode, alpha: 0.0, completion: { [weak emptyNode] _ in - emptyNode?.removeFromSupernode() - }) - } + needsEmptyNode = false + isLoading = isLoadingValue } else { - if let currentNode = strongSelf.emptyNode { - currentNode.updateIsLoading(isLoading) - } else { - let subject: ChatListEmptyNode.Subject - if let filter = filter { - var showEdit = true - if case let .filter(_, _, _, data) = filter { - if data.excludeRead && data.includePeers.peers.isEmpty && data.includePeers.pinnedPeers.isEmpty { - showEdit = false - } - } - subject = .filter(showEdit: showEdit) - } else { - if case .forum = location { - subject = .forum - } else { - subject = .chats - } - } - - let emptyNode = ChatListEmptyNode(context: context, subject: subject, isLoading: isLoading, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, action: { - self?.emptyAction(filter) - }, secondaryAction: { - self?.secondaryEmptyAction() - }) - strongSelf.emptyNode = emptyNode - strongSelf.addSubnode(emptyNode) - if let (size, insets, _, _, _, _) = strongSelf.validLayout { - let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) - emptyNode.frame = emptyNodeFrame - emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate) - } - emptyNode.alpha = 0.0 - transition.updateAlpha(node: emptyNode, alpha: 1.0) - } + needsEmptyNode = true } - if !isLoading { + if !isLoadingValue { strongSelf.becameEmpty(filter) } - case .notEmpty: - if let emptyNode = strongSelf.emptyNode { - strongSelf.emptyNode = nil - transition.updateAlpha(node: emptyNode, alpha: 0.0, completion: { [weak emptyNode] _ in - emptyNode?.removeFromSupernode() - }) - } + case let .notEmpty(_, onlyGeneralThreadValue): + needsEmptyNode = onlyGeneralThreadValue + hasOnlyGeneralThread = onlyGeneralThreadValue } + + if needsEmptyNode { + if let currentNode = strongSelf.emptyNode { + currentNode.updateIsLoading(isLoading) + } else { + let subject: ChatListEmptyNode.Subject + if let filter = filter { + var showEdit = true + if case let .filter(_, _, _, data) = filter { + if data.excludeRead && data.includePeers.peers.isEmpty && data.includePeers.pinnedPeers.isEmpty { + showEdit = false + } + } + subject = .filter(showEdit: showEdit) + } else { + if case .forum = location { + subject = .forum(hasGeneral: hasOnlyGeneralThread) + } else { + subject = .chats + } + } + + let emptyNode = ChatListEmptyNode(context: context, subject: subject, isLoading: isLoading, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, action: { + self?.emptyAction(filter) + }, secondaryAction: { + self?.secondaryEmptyAction() + }) + strongSelf.emptyNode = emptyNode + strongSelf.addSubnode(emptyNode) + if let (size, insets, _, _, _, _) = strongSelf.validLayout { + let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) + emptyNode.frame = emptyNodeFrame + emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate) + } + emptyNode.alpha = 0.0 + transition.updateAlpha(node: emptyNode, alpha: 1.0) + } + } else if let emptyNode = strongSelf.emptyNode { + strongSelf.emptyNode = nil + transition.updateAlpha(node: emptyNode, alpha: 0.0, completion: { [weak emptyNode] _ in + emptyNode?.removeFromSupernode() + }) + } + + if needsShimmerNode { strongSelf.shimmerNodeOffset = shimmerNodeOffset if strongSelf.emptyShimmerEffectNode == nil { @@ -1191,7 +1198,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { var peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? var dismissSelfIfCompletedPresentation: (() -> Void)? var isEmptyUpdated: ((Bool) -> Void)? - var emptyListAction: (() -> Void)? + var emptyListAction: ((EnginePeer.Id?) -> Void)? var cancelEditing: (() -> Void)? let debugListView = ListView() @@ -1243,11 +1250,11 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { strongSelf.dismissSelfIfCompletedPresentation?() } } - filterEmptyAction = { [weak self] filter in + filterEmptyAction = { [weak self] _ in guard let strongSelf = self else { return } - strongSelf.emptyListAction?() + strongSelf.emptyListAction?(nil) } secondaryEmptyAction = { [weak self] in @@ -1629,7 +1636,12 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { func setInlineChatList(location: ChatListControllerLocation?) { if let location = location { if self.inlineStackContainerNode?.location != location { - let inlineStackContainerNode = ChatListContainerNode(context: self.context, location: location, previewing: false, controlsHistoryPreload: false, isInlineMode: true, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filterBecameEmpty: { _ in }, filterEmptyAction: { _ in }, secondaryEmptyAction: {}) + var forumPeerId: EnginePeer.Id? + if case let .forum(peerId) = location { + forumPeerId = peerId + } + + let inlineStackContainerNode = ChatListContainerNode(context: self.context, location: location, previewing: false, controlsHistoryPreload: false, isInlineMode: true, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filterBecameEmpty: { _ in }, filterEmptyAction: { [weak self] _ in self?.emptyListAction?(forumPeerId) }, secondaryEmptyAction: {}) inlineStackContainerNode.leftSeparatorLayer.isHidden = false diff --git a/submodules/ChatListUI/Sources/ChatListEmptyNode.swift b/submodules/ChatListUI/Sources/ChatListEmptyNode.swift index 50ce74a103..39f0bbfb70 100644 --- a/submodules/ChatListUI/Sources/ChatListEmptyNode.swift +++ b/submodules/ChatListUI/Sources/ChatListEmptyNode.swift @@ -14,7 +14,7 @@ final class ChatListEmptyNode: ASDisplayNode { enum Subject { case chats case filter(showEdit: Bool) - case forum + case forum(hasGeneral: Bool) } private let action: () -> Void private let secondaryAction: () -> Void @@ -131,7 +131,6 @@ final class ChatListEmptyNode: ASDisplayNode { let text: String var descriptionText = "" let buttonText: String - var secondaryButtonText = "" switch self.subject { case .chats: text = strings.ChatList_EmptyChatList @@ -143,7 +142,7 @@ final class ChatListEmptyNode: ASDisplayNode { case .forum: text = strings.ChatList_EmptyTopicsTitle buttonText = strings.ChatList_EmptyTopicsCreate - secondaryButtonText = strings.ChatList_EmptyTopicsShowAsMessages + descriptionText = strings.ChatList_EmptyTopicsDescription } let string = NSMutableAttributedString(string: text, font: Font.medium(17.0), textColor: theme.list.itemPrimaryTextColor) let descriptionString = NSAttributedString(string: descriptionText, font: Font.regular(14.0), textColor: theme.list.itemSecondaryTextColor) @@ -152,8 +151,6 @@ final class ChatListEmptyNode: ASDisplayNode { self.descriptionNode.attributedText = descriptionString self.buttonNode.title = buttonText - self.secondaryButtonNode.setAttributedTitle(NSAttributedString(string: secondaryButtonText, font: Font.regular(17.0), textColor: theme.list.itemAccentColor), for: .normal) - self.secondaryButtonNode.isHidden = secondaryButtonText.isEmpty self.activityIndicator.type = .custom(theme.list.itemAccentColor, 22.0, 1.0, false) @@ -186,16 +183,21 @@ final class ChatListEmptyNode: ASDisplayNode { let textSize = self.textNode.updateLayout(CGSize(width: size.width - 40.0, height: size.height)) let descriptionSize = self.descriptionNode.updateLayout(CGSize(width: size.width - 40.0, height: size.height)) - let buttonSideInset: CGFloat = 16.0 - let buttonWidth = size.width - buttonSideInset * 2.0 + let buttonSideInset: CGFloat = 32.0 + let buttonWidth = min(270.0, size.width - buttonSideInset * 2.0) let buttonHeight = self.buttonNode.updateLayout(width: buttonWidth, transition: transition) let buttonSize = CGSize(width: buttonWidth, height: buttonHeight) let secondaryButtonSize = self.secondaryButtonNode.measure(CGSize(width: buttonWidth, height: .greatestFiniteMagnitude)) + var threshold: CGFloat = 0.0 + if case .forum = self.subject { + threshold = 80.0 + } + let contentHeight = self.animationSize.height + animationSpacing + textSize.height + buttonSize.height var contentOffset: CGFloat = 0.0 - if size.height < contentHeight { + if size.height < contentHeight + threshold { contentOffset = -self.animationSize.height - animationSpacing + 44.0 transition.updateAlpha(node: self.animationNode, alpha: 0.0) } else { @@ -224,7 +226,12 @@ final class ChatListEmptyNode: ASDisplayNode { bottomInset += secondaryButtonSize.height + 23.0 } - let buttonFrame = CGRect(origin: CGPoint(x: floor((size.width - buttonSize.width) / 2.0), y: size.height - buttonHeight - bottomInset), size: buttonSize) + let buttonFrame: CGRect + if case .forum = self.subject { + buttonFrame = CGRect(origin: CGPoint(x: floor((size.width - buttonSize.width) / 2.0), y: descriptionFrame.maxY + 20.0), size: buttonSize) + } else { + buttonFrame = CGRect(origin: CGPoint(x: floor((size.width - buttonSize.width) / 2.0), y: size.height - buttonHeight - bottomInset), size: buttonSize) + } transition.updateFrame(node: self.buttonNode, frame: buttonFrame) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 52348dde50..0d2ca91ea3 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -759,7 +759,7 @@ public enum ChatListNodeScrollPosition { } public enum ChatListNodeEmptyState: Equatable { - case notEmpty(containsChats: Bool) + case notEmpty(containsChats: Bool, onlyGeneralThread: Bool) case empty(isLoading: Bool, hasArchiveInfo: Bool) } @@ -2244,16 +2244,30 @@ public final class ChatListNode: ListView { isEmptyState = .empty(isLoading: isLoading, hasArchiveInfo: false) } else { var containsChats = false + var threadCount = 0 + var hasGeneral = false loop: for entry in transition.chatListView.filteredEntries { switch entry { case .GroupReferenceEntry, .HoleEntry, .PeerEntry: containsChats = true - break loop + if case .forum = strongSelf.location { + if case let .PeerEntry(_, _, _, _, _, _, _, threadInfo, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry, let threadInfo { + if threadInfo.id == 1 { + hasGeneral = true + } + threadCount += 1 + if threadCount > 1 { + break loop + } + } + } else { + break loop + } case .ArchiveIntro, .HeaderEntry, .AdditionalCategory: break } } - isEmptyState = .notEmpty(containsChats: containsChats) + isEmptyState = .notEmpty(containsChats: containsChats, onlyGeneralThread: hasGeneral && threadCount == 1) } var insertedPeerIds: [EnginePeer.Id] = [] diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index 358e9d3454..06471c28f0 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -334,6 +334,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { let enabled: Bool let highlighted: Bool public let selectable: Bool + let animateFirstAvatarTransition: Bool public let sectionId: ItemListSectionId let action: (() -> Void)? let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void @@ -350,7 +351,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { let displayDecorations: Bool let disableInteractiveTransitionIfNecessary: Bool - public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: EnginePeer, threadInfo: EngineMessageHistoryThread.Info? = nil, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: EnginePeer.Presence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, highlighted: Bool = false, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, removePeer: @escaping (EnginePeer.Id) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, noCorners: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil, displayDecorations: Bool = true, disableInteractiveTransitionIfNecessary: Bool = false) { + public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: EnginePeer, threadInfo: EngineMessageHistoryThread.Info? = nil, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: EnginePeer.Presence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, highlighted: Bool = false, selectable: Bool, animateFirstAvatarTransition: Bool = true, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, removePeer: @escaping (EnginePeer.Id) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, noCorners: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil, displayDecorations: Bool = true, disableInteractiveTransitionIfNecessary: Bool = false) { self.presentationData = presentationData self.dateTimeFormat = dateTimeFormat self.nameDisplayOrder = nameDisplayOrder @@ -370,6 +371,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { self.enabled = enabled self.highlighted = highlighted self.selectable = selectable + self.animateFirstAvatarTransition = animateFirstAvatarTransition self.sectionId = sectionId self.action = action self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions @@ -1289,6 +1291,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo if item.peer.isDeleted { overrideImage = .deletedIcon } + strongSelf.avatarNode.imageNode.animateFirstTransition = item.animateFirstAvatarTransition strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) } } diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index 789cd19ce2..df3e542697 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -107,6 +107,7 @@ swift_library( "//submodules/TelegramUI/Components/EntityKeyboard:EntityKeyboard", "//submodules/PersistentStringHash:PersistentStringHash", "//submodules/TelegramUI/Components/NotificationPeerExceptionController", + "//submodules/TelegramUI/Components/ChatTimerScreen", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/ChatTimerScreen/Sources/ChatTimerScreen.swift b/submodules/TelegramUI/Components/ChatTimerScreen/Sources/ChatTimerScreen.swift index ccf39e1dd8..586b4780c9 100644 --- a/submodules/TelegramUI/Components/ChatTimerScreen/Sources/ChatTimerScreen.swift +++ b/submodules/TelegramUI/Components/ChatTimerScreen/Sources/ChatTimerScreen.swift @@ -30,7 +30,6 @@ public final class ChatTimerScreen: ViewController { private var animatedIn = false private let context: AccountContext - private let peerId: PeerId private let style: ChatTimerScreenStyle private let mode: ChatTimerScreenMode private let currentTime: Int32? @@ -40,9 +39,8 @@ public final class ChatTimerScreen: ViewController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peerId: PeerId, style: ChatTimerScreenStyle, mode: ChatTimerScreenMode = .sendTimer, currentTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) { + public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, style: ChatTimerScreenStyle, mode: ChatTimerScreenMode = .sendTimer, currentTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) { self.context = context - self.peerId = peerId self.style = style self.mode = mode self.currentTime = currentTime diff --git a/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/AntiSpamTooltip.pdf b/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/AntiSpamTooltip.pdf deleted file mode 100644 index b8af1388d8..0000000000 --- a/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/AntiSpamTooltip.pdf +++ /dev/null @@ -1,112 +0,0 @@ -%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.199997 1.907497 cm -1.000000 1.000000 1.000000 scn -0.000000 12.592503 m -0.000000 18.498425 l -0.000000 19.400753 0.000000 19.851917 0.142046 20.246223 c -0.267605 20.594761 0.472146 20.909500 0.739650 21.165794 c -1.042280 21.455738 1.454996 21.639168 2.280427 22.006027 c -7.680857 24.406218 l -8.829472 24.916712 9.403779 25.171961 10.000750 25.272770 c -10.529839 25.362116 11.070163 25.362116 11.599251 25.272770 c -12.196222 25.171961 12.770529 24.916714 13.919143 24.406218 c -19.319572 22.006027 l -20.145004 21.639168 20.557720 21.455738 20.860350 21.165794 c -21.127855 20.909500 21.332396 20.594761 21.457954 20.246223 c -21.600000 19.851917 21.600000 19.400753 21.600000 18.498423 c -21.600000 12.592503 l -21.600000 4.965950 14.783872 1.126137 11.981524 -0.130262 c -11.981509 -0.130268 l -11.662810 -0.273155 11.503456 -0.344597 11.202699 -0.395788 c -10.999416 -0.430387 10.600584 -0.430387 10.397303 -0.395788 c -10.096541 -0.344597 9.937186 -0.273151 9.618476 -0.130262 c -6.816126 1.126139 0.000000 4.965952 0.000000 12.592503 c -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 7.199997 8.199517 cm -0.274510 0.294118 0.298039 scn -0.989925 6.863103 m -4.855387 8.547224 7.432969 9.657499 8.722668 10.193930 c -12.405018 11.725546 13.170178 11.991605 13.668900 12.000390 c -13.778588 12.002322 14.023846 11.975138 14.182714 11.846229 c -14.316857 11.737380 14.353765 11.590341 14.371427 11.487141 c -14.389089 11.383940 14.411081 11.148846 14.393599 10.965151 c -14.194051 8.868484 13.330610 3.780426 12.891341 1.432123 c -12.705469 0.438469 12.339483 0.105302 11.985166 0.072697 c -11.215152 0.001839 10.630439 0.581574 9.884643 1.070453 c -8.717619 1.835451 8.058326 2.311666 6.925527 3.058163 c -5.616383 3.920870 6.465046 4.395029 7.211124 5.169937 c -7.406376 5.372734 10.799074 8.458654 10.864739 8.738596 c -10.872952 8.773607 10.880574 8.904113 10.803043 8.973024 c -10.725513 9.041937 10.611083 9.018372 10.528507 8.999630 c -10.411459 8.973064 8.547124 7.740808 4.935502 5.302861 c -4.406317 4.939481 3.926997 4.762432 3.497544 4.771710 c -3.024105 4.781938 2.113399 5.039400 1.436383 5.259471 c -0.605995 5.529397 -0.053981 5.672108 0.003489 6.130527 c -0.033422 6.369299 0.362234 6.613492 0.989925 6.863103 c -h -f* -n -Q - -endstream -endobj - -3 0 obj - 2275 -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 -0000002365 00000 n -0000002388 00000 n -0000002561 00000 n -0000002635 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2694 -%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/Contents.json deleted file mode 100644 index c2e19c2189..0000000000 --- a/submodules/TelegramUI/Images.xcassets/Chat/AntiSpamTooltipIcon.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "AntiSpamTooltip.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/submodules/TelegramUI/Resources/Animations/anim_antispam.json b/submodules/TelegramUI/Resources/Animations/anim_antispam.json new file mode 100644 index 0000000000..2e28cfb500 --- /dev/null +++ b/submodules/TelegramUI/Resources/Animations/anim_antispam.json @@ -0,0 +1 @@ +{"tgs":1,"v":"5.5.2","fr":60,"ip":0,"op":62,"w":512,"h":512,"nm":"MAIN 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 19","parent":2,"sr":1,"ks":{"p":{"a":0,"k":[11,81,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[22.633,80.31],[48,25]],"o":[[-31,-110],[-40.692,-21.194]],"v":[[142,74],[-61.5,-172]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":53},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[138]},{"t":49,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":23},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"t":41,"s":[100],"h":1},{"t":48,"s":[0],"h":1}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[40.327,73.046],[64,-122.5]],"o":[[-53,-96],[-66.658,127.588]],"v":[[214,-140],[-41,-156.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":52},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[138]},{"t":52,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":18},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":40,"op":52,"st":46,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 18","sr":1,"ks":{"p":{"a":0,"k":[256,266,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[244,-168],[-73.5,-71.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":44},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[-138]},{"t":41,"s":[138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":30},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":34,"op":42,"st":33,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 17","parent":4,"sr":1,"ks":{"p":{"a":0,"k":[17.2,33.289,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[23.268,80.129],[67,19]],"o":[[-26.772,-92.194],[-44.14,-12.517]],"v":[[116.402,52.791],[-77,-127]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":53},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[138]},{"t":40,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":23},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[47.235,68.781],[80,-106]],"o":[[-57,-83],[-86.717,114.9]],"v":[[236.737,-175.327],[-74,-158]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":52},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[138]},{"t":40,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":17},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":29,"op":40,"st":34,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 16","sr":1,"ks":{"r":{"a":0,"k":19},"p":{"a":0,"k":[226,366,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[245.1,-201.69],[-99,-87]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":44},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[-138]},{"t":29,"s":[138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":30},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":22,"op":29,"st":21,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 15","parent":6,"sr":1,"ks":{"p":{"a":0,"k":[11,46,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[42.482,71.814],[43,29]],"o":[[-42,-71],[-38.038,-25.654]],"v":[[33,11],[-77,-127]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":53},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[138]},{"t":24,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":22},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[61.92,55.928],[64,-61]],"o":[[-31,-28],[-104.202,99.318]],"v":[[141,-191],[-74,-158]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":52},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[138]},{"t":24,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":22},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":14,"op":24,"st":20,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"p":{"a":0,"k":[256,256,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[186,-254],[-99,-87]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":44},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[-138]},{"t":15,"s":[138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":30},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":8,"op":16,"st":7,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 21","parent":8,"sr":1,"ks":{"p":{"a":0,"k":[21,46,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[65.56,51.612],[59,13.5]],"o":[[-23.5,-18.5],[-44.724,-10.234]],"v":[[112.5,-63.5],[-54,-143.5]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":53},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[138]},{"t":15,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":16},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":1,"k":[{"t":3,"s":[100],"h":1},{"t":14,"s":[0],"h":1}]},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 3","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[10.101,82.825],[41,50]],"o":[[-5,-41],[-29.092,-35.478]],"v":[[-11,83],[-77,-127]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":53},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[138]},{"t":18,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":22},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2","bm":0,"hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[47.235,68.781],[80,-106]],"o":[[-57,-83],[-86.717,114.9]],"v":[[214,-140],[-74,-158]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":52},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[138]},{"t":18,"s":[-138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":22},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":7,"op":19,"st":13,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 20","sr":1,"ks":{"p":{"a":0,"k":[256,416,0]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[246,49],[-70,-102]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":44},"e":{"a":0,"k":55},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[-138]},{"t":7,"s":[138]}]},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":30},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":3,"op":8,"st":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shield 2","sr":1,"ks":{"r":{"a":1,"k":[{"i":{"x":[0.501],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[48]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":8,"s":[-14]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":15,"s":[-7]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":21,"s":[-15]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28,"s":[-8]},{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":34,"s":[-17]},{"i":{"x":[0.41],"y":[1]},"o":{"x":[0.566],"y":[0]},"t":40,"s":[-6]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.306],"y":[0]},"t":47,"s":[-10]},{"t":61,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[295.472,423.265,0],"to":[-16.667,0,0],"ti":[7.667,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.249,"y":0},"t":10,"s":[195.472,423.265,0],"to":[-0.606,0,0],"ti":[0.375,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0},"t":14,"s":[194.006,423.265,0],"to":[-2.009,0,0],"ti":[-2.739,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":20,"s":[185.901,423.265,0],"to":[1.121,0,0],"ti":[-3.123,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0},"t":27,"s":[202.744,423.265,0],"to":[3.541,0,0],"ti":[-0.592,0,0]},{"i":{"x":0.41,"y":1},"o":{"x":0.167,"y":0},"t":33,"s":[197.405,423.265,0],"to":[0.206,0,0],"ti":[-3.02,0,0]},{"i":{"x":0.707,"y":1},"o":{"x":0.352,"y":0},"t":39,"s":[213.726,423.265,0],"to":[2.606,0,0],"ti":[-0.59,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.4,"y":0},"t":46,"s":[219.472,423.265,0],"to":[10,0,0],"ti":[-6,0,0]},{"t":58,"s":[255.472,423.265,0]}]},"a":{"a":0,"k":[-5.127,171.315,0]},"s":{"a":1,"k":[{"i":{"x":[0.41,0.41,0.41],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.824]},"t":0,"s":[38.824,33,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":10,"s":[102,102,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":14,"s":[102,102,100]},{"i":{"x":[0.41,0.41,0.41],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,-0.018]},"t":17,"s":[97,97,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":23,"s":[102,102,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":27,"s":[102,102,100]},{"i":{"x":[0.41,0.41,0.41],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,-0.351]},"t":30,"s":[97,97,100]},{"t":36,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[6.053,-2.446],[41.492,-19.234],[-7.069,-1.676],[0,0],[-8.649,5.944],[0,0],[3.491,-3.211],[0,0],[-7.453,-5.901],[-17.07,-12.037],[-1.639,11.142]],"o":[[1.133,-6.43],[-36.83,14.879],[-6.591,3.055],[0,0],[10.212,2.42],[0,0],[3.94,-2.64],[0,0],[-6.759,6.685],[14.513,11.489],[9.204,6.49],[0,0]],"v":[[91.767,-70.773],[80.475,-79.927],[-110.244,0.632],[-108.787,15.016],[-73.738,22.79],[-44.118,17.256],[30.364,-32.044],[35.102,-26.026],[-18.833,26.526],[-17.781,51.197],[39.986,95.109],[63.637,84.989]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.65,"y":0},"t":22,"s":[{"i":[[0,0],[2.965,-2.446],[20.324,-19.234],[-3.463,-1.676],[0,0],[-4.237,5.944],[0,0],[1.71,-3.211],[0,0],[-3.651,-5.901],[-8.361,-12.037],[-0.803,11.142]],"o":[[0.555,-6.43],[-18.04,14.879],[-3.229,3.055],[0,0],[5.002,2.42],[0,0],[1.93,-2.64],[0,0],[-3.311,6.685],[7.109,11.489],[4.508,6.49],[0,0]],"v":[[63.345,-70.773],[57.814,-79.927],[-35.607,0.632],[-34.893,15.016],[-17.725,22.79],[-3.216,17.256],[33.268,-32.044],[35.589,-26.026],[9.169,26.526],[9.685,51.197],[37.981,95.109],[49.566,84.989]],"c":true}]},{"t":59,"s":[{"i":[[0,0],[6.053,-2.446],[41.492,-19.234],[-7.069,-1.676],[0,0],[-8.649,5.944],[0,0],[3.491,-3.211],[0,0],[-7.453,-5.901],[-17.07,-12.037],[-1.639,11.142]],"o":[[1.133,-6.43],[-36.83,14.879],[-6.591,3.055],[0,0],[10.212,2.42],[0,0],[3.94,-2.64],[0,0],[-6.759,6.685],[14.513,11.489],[9.204,6.49],[0,0]],"v":[[91.767,-70.773],[80.475,-79.927],[-110.244,0.632],[-108.787,15.016],[-73.738,22.79],[-44.118,17.256],[30.364,-32.044],[35.102,-26.026],[-18.833,26.526],[-17.781,51.197],[39.986,95.109],[63.637,84.989]],"c":true}]}]},"nm":"Path 1","hd":false},{"ty":"tr","p":{"a":0,"k":[5.804,8.673]},"a":{"a":0,"k":[5.804,8.673]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[100,100]},{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[90,90]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":14,"s":[100,100]},{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[85,85]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":23,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[100,100]},{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[90,90]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[100,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[100,100]},{"i":{"x":[0.41,0.41],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[90,90]},{"t":48,"s":[100,100]}]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Group 1","bm":0,"hd":false},{"ind":1,"ty":"sh","ks":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[{"i":[[0,0],[0,0],[-64.8,-27.595],[-1.194,-27.419],[0,0],[29.3,0],[17.61,9.401],[24.991,36.518],[0.881,34.208],[0,0],[0,0],[-21.6,0]],"o":[[0,0],[21.6,1.58],[0,0],[0,0],[0,116.112],[-7.822,0],[-28.476,-15.201],[-17.445,-25.491],[0,0],[1.461,-27.963],[65.433,-30.86],[0,0]],"v":[[-6.1,-185.7],[-3.1,-185.7],[126.5,-133.12],[155.4,-90.885],[155.4,5.1],[-4.6,191.85],[-44.872,177.51],[-134.056,98.923],[-164.6,9.032],[-164.6,-89.2],[-135.466,-129.855],[-6.1,-185.7]],"c":true}]},{"i":{"x":0.5,"y":1},"o":{"x":0.65,"y":0},"t":22,"s":[{"i":[[0,0],[0,0],[-31.321,-27.595],[-0.577,-27.419],[0,0],[15.566,0],[9.355,9.401],[13.277,36.518],[0.468,34.208],[0,0],[0,0],[-10.44,0]],"o":[[0,0],[10.44,1.58],[0,0],[0,0],[0,116.112],[-4.155,0],[-15.128,-15.201],[-9.268,-25.491],[0,0],[0.776,-27.963],[34.761,-30.86],[0,0]],"v":[[2.34,-185.7],[3.79,-185.7],[66.431,-133.12],[80.4,-90.885],[80.4,5.1],[-4.6,191.85],[-25.994,177.51],[-73.374,98.923],[-89.6,9.032],[-89.6,-89.2],[-74.123,-129.855],[2.34,-185.7]],"c":true}]},{"t":59,"s":[{"i":[[0,0],[0,0],[-64.8,-27.595],[-1.194,-27.419],[0,0],[29.3,0],[17.61,9.401],[24.991,36.518],[0.881,34.208],[0,0],[0,0],[-21.6,0]],"o":[[0,0],[21.6,1.58],[0,0],[0,0],[0,116.112],[-7.822,0],[-28.476,-15.201],[-17.445,-25.491],[0,0],[1.461,-27.963],[65.433,-30.86],[0,0]],"v":[[-6.1,-185.7],[-3.1,-185.7],[126.5,-133.12],[155.4,-90.885],[155.4,5.1],[-4.6,191.85],[-44.872,177.51],[-134.056,98.923],[-164.6,9.032],[-164.6,-89.2],[-135.466,-129.855],[-6.1,-185.7]],"c":true}]}]},"nm":"Path 2","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"User-promoted","bm":0,"hd":false}],"ip":1,"op":180,"st":-102,"bm":0}]} \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift index b32b40b6f0..4706b3ea44 100644 --- a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift @@ -171,7 +171,7 @@ final class ChatBotInfoItemNode: ListViewItemNode { break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji: return .waitForSingleTap } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index b915cdb102..39206003d2 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3590,6 +3590,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }, displayPremiumStickerTooltip: { [weak self] file, message in self?.displayPremiumStickerTooltip(file: file, message: message) + }, displayEmojiPackTooltip: { [weak self] file, message in + self?.displayEmojiPackTooltip(file: file, message: message) }, openPeerContextMenu: { [weak self] peer, messageId, node, rect, gesture in guard let strongSelf = self else { return @@ -13581,6 +13583,56 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } + private func displayEmojiPackTooltip(file: TelegramMediaFile, message: Message) { + let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) + guard !premiumConfiguration.isPremiumDisabled else { + return + } + + var currentOverlayController: UndoOverlayController? + + self.window?.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + currentOverlayController = controller + } + }) + self.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + currentOverlayController = controller + } + return true + }) + + if let currentOverlayController = currentOverlayController { + if case .sticker = currentOverlayController.content { + return + } + currentOverlayController.dismissWithCommitAction() + } + + var stickerPackReference: StickerPackReference? + for attribute in file.attributes { + if case let .CustomEmoji(_, _, packReference) = attribute { + stickerPackReference = packReference + break + } + } + + if let stickerPackReference = stickerPackReference { + let _ = (self.context.engine.stickers.loadedStickerPack(reference: stickerPackReference, forceActualized: false) + |> deliverOnMainQueue).start(next: { [weak self] stickerPack in + if let strongSelf = self, case let .result(info, _, _) = stickerPack { + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: nil, text: strongSelf.presentationData.strings.Stickers_EmojiPackInfoText(info.title).string, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView, customAction: nil), elevatedLayout: false, action: { [weak self] action in + if let strongSelf = self, action == .undo { + strongSelf.presentEmojiList(references: [stickerPackReference]) + } + return false + }), in: .current) + } + }) + } + } + private func displayDiceTooltip(dice: TelegramMediaDice) { guard let _ = dice.value else { return @@ -17171,10 +17223,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } private func presentTimerPicker(style: ChatTimerScreenStyle = .default, selectedTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) { - guard case let .peer(peerId) = self.chatLocation else { - return - } - let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peerId: peerId, style: style, currentTime: selectedTime, dismissByTapOutside: dismissByTapOutside, completion: { time in + let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, style: style, currentTime: selectedTime, dismissByTapOutside: dismissByTapOutside, completion: { time in completion(time) }) self.chatDisplayNode.dismissInput() @@ -17231,7 +17280,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peerId: peer.id, style: .default, mode: .autoremove, currentTime: self.presentationInterfaceState.autoremoveTimeout, dismissByTapOutside: true, completion: { [weak self] value in + let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, style: .default, mode: .autoremove, currentTime: self.presentationInterfaceState.autoremoveTimeout, dismissByTapOutside: true, completion: { [weak self] value in guard let strongSelf = self else { return } diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index 14b6a9e014..b15069eb58 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -134,6 +134,7 @@ public final class ChatControllerInteraction { let displayDiceTooltip: (TelegramMediaDice) -> Void let animateDiceSuccess: (Bool, Bool) -> Void let displayPremiumStickerTooltip: (TelegramMediaFile, Message) -> Void + let displayEmojiPackTooltip: (TelegramMediaFile, Message) -> Void let openPeerContextMenu: (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void let openMessageReplies: (MessageId, Bool, Bool) -> Void let openReplyThreadOriginalMessage: (Message) -> Void @@ -243,6 +244,7 @@ public final class ChatControllerInteraction { displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, animateDiceSuccess: @escaping (Bool, Bool) -> Void, displayPremiumStickerTooltip: @escaping (TelegramMediaFile, Message) -> Void, + displayEmojiPackTooltip: @escaping (TelegramMediaFile, Message) -> Void, openPeerContextMenu: @escaping (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void, openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void, openReplyThreadOriginalMessage: @escaping (Message) -> Void, @@ -335,6 +337,7 @@ public final class ChatControllerInteraction { self.displayDiceTooltip = displayDiceTooltip self.animateDiceSuccess = animateDiceSuccess self.displayPremiumStickerTooltip = displayPremiumStickerTooltip + self.displayEmojiPackTooltip = displayEmojiPackTooltip self.openPeerContextMenu = openPeerContextMenu self.openMessageReplies = openMessageReplies self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 62340e33f6..3f4ce2db16 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -2126,7 +2126,17 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } - if let item = self.item, self.imageNode.frame.contains(location) { + if let item = self.item, let emojiString = self.emojiString, emojiString.emojis.count > 1 { + if let (_, attributes) = self.textNode.textNode.attributesAtPoint(self.view.convert(location, to: self.textNode.textNode.view)) { + for (_, attribute) in attributes { + if let attribute = attribute as? ChatTextInputTextCustomEmojiAttribute, let file = attribute.file { + return .optionalAction({ + item.controllerInteraction.displayEmojiPackTooltip(file, item.message) + }) + } + } + } + } else if let item = self.item, self.imageNode.frame.contains(location) { let emojiTapAction: (Bool) -> InternalBubbleTapAction? = { shouldPlay in let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F499, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D] let heart = 0x2764 diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift index 0a0fba5028..a470c66ff6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift @@ -123,6 +123,7 @@ enum ChatMessageBubbleContentTapAction { case openPollResults(Data) case copy(String) case largeEmoji(String, String?, TelegramMediaFile) + case customEmoji(TelegramMediaFile) } final class ChatMessageBubbleContentItem { diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 8cbed73017..5c9b491be6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -964,7 +964,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji: return .waitForSingleTap } } @@ -3742,6 +3742,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode item.controllerInteraction.openLargeEmojiInfo(emoji, fitz, file) }) } + case let .customEmoji(file): + if let item = self.item { + return .optionalAction({ + item.controllerInteraction.displayEmojiPackTooltip(file, item.message) + }) + } } } return nil @@ -3826,6 +3832,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode break case .largeEmoji: break + case .customEmoji: + break } } if let tapMessage = tapMessage { diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 020d1bd160..d305d027ae 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -580,6 +580,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { return .bankCard(bankCard) } else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String { return .copy(pre) + } else if let emoji = attributes[NSAttributedString.Key(rawValue: ChatTextInputAttributes.customEmoji.rawValue)] as? ChatTextInputTextCustomEmojiAttribute, let file = emoji.file { + return .customEmoji(file) } else { if let item = self.item, item.message.text.count == 1, !item.presentationData.largeEmoji { let (emoji, fitz) = item.message.text.basicEmoji diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 330977e2e3..04261503ed 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -535,6 +535,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in @@ -789,7 +790,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { if peer.id == antiSpamBotConfiguration.antiSpamBotId { self.dismissAllTooltips() - self.presentController(UndoOverlayController(presentationData: self.presentationData, content: .image(image: UIImage(bundleImageName: "Chat/AntiSpamTooltipIcon")!, title: self.presentationData.strings.Group_AdminLog_AntiSpamTitle, text: self.presentationData.strings.Group_AdminLog_AntiSpamText, undo: false), elevatedLayout: true, action: { [weak self] action in + self.presentController(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_antispam", scale: 0.066, colors: [:], title: self.presentationData.strings.Group_AdminLog_AntiSpamTitle, text: self.presentationData.strings.Group_AdminLog_AntiSpamText, customUndoText: nil), elevatedLayout: true, action: { [weak self] action in if let strongSelf = self { if case .info = action { let _ = strongSelf.getNavigationController()?.popViewController(animated: true) @@ -923,8 +924,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { |> deliverOnMainQueue).start(), forKey: message.id) Queue.mainQueue().after(0.2, { - let content: UndoOverlayContent = .image(image: UIImage(bundleImageName: "Chat/AntiSpamTooltipIcon")!, title: nil, text: strongSelf.presentationData.strings.Group_AdminLog_AntiSpamFalsePositiveReportedText, undo: false) - strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil) + strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_antispam", scale: 0.066, colors: [:], title: nil, text: strongSelf.presentationData.strings.Group_AdminLog_AntiSpamFalsePositiveReportedText, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil) }) } })), at: 0 diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift index ce5e644bd7..ecaa5f3354 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift @@ -529,7 +529,7 @@ 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: 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: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil) + 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: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil) return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)) } case .participantJoin, .participantLeave: diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 892a074980..72ecc4dc8c 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -146,6 +146,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 2aa1b1602e..2f4c04b354 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -139,6 +139,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift index 8330e13cb7..7a089aabf9 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift @@ -23,6 +23,7 @@ final class PeerInfoScreenMemberItem: PeerInfoScreenItem { let enclosingPeer: Peer? let member: PeerInfoMember let badge: String? + let isAccount: Bool let action: ((PeerInfoScreenMemberItemAction) -> Void)? let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? @@ -32,6 +33,7 @@ final class PeerInfoScreenMemberItem: PeerInfoScreenItem { enclosingPeer: Peer?, member: PeerInfoMember, badge: String? = nil, + isAccount: Bool, action: ((PeerInfoScreenMemberItemAction) -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil ) { @@ -40,6 +42,7 @@ final class PeerInfoScreenMemberItem: PeerInfoScreenItem { self.enclosingPeer = enclosingPeer self.member = member self.badge = badge + self.isAccount = isAccount self.action = action self.contextAction = contextAction } @@ -188,7 +191,7 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { itemText = .presence } - let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: EnginePeer(item.member.peer), height: itemHeight, presence: item.member.presence.flatMap(EnginePeer.Presence.init), text: itemText, label: itemLabel, editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: nil), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in + let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: EnginePeer(item.member.peer), height: itemHeight, presence: item.member.presence.flatMap(EnginePeer.Presence.init), text: itemText, label: itemLabel, editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: nil), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: false, animateFirstAvatarTransition: !item.isAccount, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in }, removePeer: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 24c10943ee..06acda1ece 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -322,6 +322,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { } var tapped: (() -> Void)? + var emojiTapped: (() -> Void)? var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? private var isFirstAvatarLoading = true @@ -365,6 +366,12 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { self.tapped?() } } + + @objc private func emojiTapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.emojiTapped?() + } + } func updateTransitionFraction(_ fraction: CGFloat, transition: ContainedViewLayoutTransition) { if let videoNode = self.videoNode { @@ -409,6 +416,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { self.containerNode.isGestureEnabled = false } + self.avatarNode.imageNode.animateFirstTransition = !isSettings self.avatarNode.setPeer(context: self.context, theme: theme, peer: EnginePeer(peer), overrideImage: overrideImage, clipStyle: .none, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true) if let threadInfo = threadInfo { @@ -443,7 +451,9 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { containerSize: CGSize(width: avatarSize, height: avatarSize) ) if let iconComponentView = iconView.view { + iconComponentView.isUserInteractionEnabled = true if iconComponentView.superview == nil { + iconComponentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.emojiTapGesture(_:)))) self.avatarNode.view.superview?.addSubview(iconComponentView) } iconComponentView.frame = CGRect(origin: CGPoint(), size: CGSize(width: avatarSize, height: avatarSize)) @@ -988,6 +998,8 @@ final class PeerInfoAvatarListNode: ASDisplayNode { } else { if let result = self.avatarContainerNode.avatarNode.view.hitTest(self.view.convert(point, to: self.avatarContainerNode.avatarNode.view), with: event) { return result + } else if let result = self.avatarContainerNode.iconView?.view?.hitTest(self.view.convert(point, to: self.avatarContainerNode.iconView?.view), with: event) { + return result } } @@ -2108,6 +2120,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var displayAvatarContextMenu: ((ASDisplayNode, ContextGesture?) -> Void)? var displayCopyContextMenu: ((ASDisplayNode, Bool, Bool) -> Void)? + var displayEmojiPackTooltip: (() -> Void)? var displayPremiumIntro: ((UIView, PeerEmojiStatus?, Signal<(TelegramMediaFile, LoadedStickerPack)?, NoError>, Bool) -> Void)? @@ -2241,6 +2254,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.avatarListNode.avatarContainerNode.contextAction = { [weak self] node, gesture in self?.displayAvatarContextMenu?(node, gesture) } + self.avatarListNode.avatarContainerNode.emojiTapped = { [weak self] in + self?.displayEmojiPackTooltip?() + } self.editingContentNode.avatarNode.tapped = { [weak self] confirm in self?.initiateAvatarExpansion(gallery: true, first: true) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index b5b3bbe1c0..d372dccb27 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -81,6 +81,7 @@ import ForumCreateTopicScreen import NotificationExceptionsScreen import ChatTimerScreen import NotificationPeerExceptionController +import StickerPackPreviewUI protocol PeerInfoScreenItem: AnyObject { var id: AnyHashable { get } @@ -705,7 +706,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p if !settings.accountsAndPeers.isEmpty { for (peerAccountContext, peer, badgeCount) in settings.accountsAndPeers { let member: PeerInfoMember = .account(peer: RenderedPeer(peer: peer._asPeer())) - items[.accounts]!.append(PeerInfoScreenMemberItem(id: member.id, context: context.sharedContext.makeTempAccountContext(account: peerAccountContext.account), enclosingPeer: nil, member: member, badge: badgeCount > 0 ? "\(compactNumericCountString(Int(badgeCount), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))" : nil, action: { action in + items[.accounts]!.append(PeerInfoScreenMemberItem(id: member.id, context: context.sharedContext.makeTempAccountContext(account: peerAccountContext.account), enclosingPeer: nil, member: member, badge: badgeCount > 0 ? "\(compactNumericCountString(Int(badgeCount), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))" : nil, isAccount: true, action: { action in switch action { case .open: interaction.switchToAccount(peerAccountContext.account.id) @@ -1297,7 +1298,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese for member in memberList { let isAccountPeer = member.id == context.account.peerId - items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, enclosingPeer: peer, member: member, action: isAccountPeer ? nil : { action in + items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, enclosingPeer: peer, member: member, isAccount: false, action: isAccountPeer ? nil : { action in switch action { case .open: interaction.openPeerInfo(member.peer, true) @@ -2600,6 +2601,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in @@ -3445,6 +3447,40 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate strongSelf.controller?.presentInGlobalOverlay(contextController) } + self.headerNode.displayEmojiPackTooltip = { [weak self] in + guard let strongSelf = self, let threadData = strongSelf.data?.threadData else { + return + } + if let icon = threadData.info.icon, icon != 0 { + let _ = (strongSelf.context.engine.stickers.resolveInlineStickers(fileIds: [icon]) + |> deliverOnMainQueue).start(next: { [weak self] files in + if let file = files.first?.value { + var stickerPackReference: StickerPackReference? + for attribute in file.attributes { + if case let .CustomEmoji(_, _, packReference) = attribute { + stickerPackReference = packReference + break + } + } + + if let stickerPackReference = stickerPackReference { + let _ = (strongSelf.context.engine.stickers.loadedStickerPack(reference: stickerPackReference, forceActualized: false) + |> deliverOnMainQueue).start(next: { [weak self] stickerPack in + if let strongSelf = self, case let .result(info, _, _) = stickerPack { + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: nil, text: strongSelf.presentationData.strings.Stickers_EmojiPackInfoText(info.title).string, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView, customAction: nil), elevatedLayout: false, action: { [weak self] action in + if let strongSelf = self, action == .undo { + strongSelf.presentEmojiList(packReference: stickerPackReference) + } + return false + }), in: .current) + } + }) + } + } + }) + } + } + if [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(peerId.namespace) { self.displayAsPeersPromise.set(context.engine.calls.cachedGroupCallDisplayAsAvailablePeers(peerId: peerId)) } @@ -4987,7 +5023,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } private func openAutoremove(currentValue: Int32?) { - let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, style: .default, mode: .autoremove, currentTime: currentValue, dismissByTapOutside: true, completion: { [weak self] value in + let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, style: .default, mode: .autoremove, currentTime: currentValue, dismissByTapOutside: true, completion: { [weak self] value in guard let strongSelf = self else { return } @@ -5016,7 +5052,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } private func openCustomMute() { - let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, style: .default, mode: .mute, currentTime: nil, dismissByTapOutside: true, completion: { [weak self] value in + let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, style: .default, mode: .mute, currentTime: nil, dismissByTapOutside: true, completion: { [weak self] value in guard let strongSelf = self else { return } @@ -7862,6 +7898,38 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } + func presentEmojiList(packReference: StickerPackReference) { + guard let peerController = self.controller else { + return + } + let presentationData = self.presentationData + let navigationController = peerController.navigationController as? NavigationController + let controller = StickerPackScreen(context: self.context, updatedPresentationData: peerController.updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: navigationController, sendEmoji: nil, actionPerformed: { [weak self] actions in + guard let strongSelf = self else { + return + } + let context = strongSelf.context + if let (info, items, action) = actions.first { + let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks + + switch action { + case .add: + strongSelf.controller?.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: false, action: { _ in + return true + })) + case let .remove(positionInList): + strongSelf.controller?.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: false, action: { action in + if case .undo = action { + let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start() + } + return true + })) + } + } + }) + peerController.present(controller, in: .window(.root)) + } + func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData @@ -8231,8 +8299,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } + private var hasQrButton = false fileprivate func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) { let offsetY = self.scrollNode.view.contentOffset.y + var transition = transition if self.isSettings, !(self.controller?.movingInHierarchy == true) { let bottomOffsetY = max(0.0, self.scrollNode.view.contentSize.height + min(83.0, self.scrollNode.view.contentInset.bottom) - offsetY - self.scrollNode.frame.height) @@ -8294,14 +8364,24 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate transition.updateFrame(node: self.headerNode.navigationButtonContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight))) self.headerNode.navigationButtonContainer.isWhite = self.headerNode.isAvatarExpanded - + var leftNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = [] var rightNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = [] if self.state.isEditing { rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .done, isForExpandedView: false)) } else { if self.isSettings { - leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false)) + var hasQrButton = false + if self.data?.globalSettings?.privacySettings?.phoneDiscoveryEnabled == true { + leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false)) + hasQrButton = true + } + if hasQrButton != self.hasQrButton { + self.hasQrButton = hasQrButton + if !transition.isAnimated { + transition = .animated(duration: 0.2, curve: .easeInOut) + } + } rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false)) rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true)) } else if peerInfoCanEdit(peer: self.data?.peer, chatLocation: self.chatLocation, threadData: self.data?.threadData, cachedData: self.data?.cachedData, isContact: self.data?.isContact) { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 0c96050740..c6b94c9429 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1333,6 +1333,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/StickerPaneSearchContentNode.swift b/submodules/TelegramUI/Sources/StickerPaneSearchContentNode.swift index 23d07053d8..8430ee3fda 100644 --- a/submodules/TelegramUI/Sources/StickerPaneSearchContentNode.swift +++ b/submodules/TelegramUI/Sources/StickerPaneSearchContentNode.swift @@ -371,7 +371,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode { let emoticons = keywords.flatMap { $0.emoticons } for emoji in emoticons { signals.append(context.engine.stickers.searchStickers(query: emoji.basicEmoji.0) - |> take(1) +// |> take(1) |> map { (emoji, $0) }) } return signals diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 7a74c8deb1..d18832fe99 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -464,7 +464,7 @@ public final class WebAppController: ViewController, AttachmentContainable { func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) { decisionHandler(.prompt) } - + func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: message, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { completionHandler()