From 489c410aca3b4badd1769de38536b24926617ea8 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 2 Aug 2022 18:29:25 +0400 Subject: [PATCH] Emoji improvements --- .../Sources/Account/Account.swift | 1 + .../Sources/State/ManagedRecentStickers.swift | 24 +++++++ .../SyncCore/SyncCore_Namespaces.swift | 1 + .../Sources/MultiAnimationRenderer.swift | 64 ++++++++++++++++--- .../Sources/ChatEntityKeyboardInputNode.swift | 4 +- .../Sources/ChatTextInputPanelNode.swift | 20 +++++- 6 files changed, 101 insertions(+), 13 deletions(-) diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 7d21c9bddd..bc41ac06c8 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -1173,6 +1173,7 @@ public class Account { } self.managedOperationsDisposable.add(managedGreetingStickers(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedPremiumStickers(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedAllPremiumStickers(postbox: self.postbox, network: self.network).start()) if !supplementary { let mediaBox = postbox.mediaBox diff --git a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift index db128a12b5..0eec62a67d 100644 --- a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift +++ b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift @@ -178,3 +178,27 @@ func managedPremiumStickers(postbox: Postbox, network: Network) -> Signal then(.complete() |> suspendAwareDelay(3.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart } + +func managedAllPremiumStickers(postbox: Postbox, network: Network) -> Signal { + let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudAllPremiumStickers, reverseHashOrder: false, forceFetch: false, fetch: { hash in + return network.request(Api.functions.messages.getStickers(emoticon: "📂⭐️", hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in + switch result { + case .stickersNotModified: + return .single(nil) + case let .stickers(_, stickers): + var items: [OrderedItemListEntry] = [] + for sticker in stickers { + if let file = telegramMediaFileFromApiDocument(sticker), let id = file.id { + if let entry = CodableEntry(RecentMediaItem(file)) { + items.append(OrderedItemListEntry(id: RecentMediaItemId(id).rawValue, contents: entry)) + } + } + } + return .single(items) + } + } + }) + return (poll |> then(.complete() |> suspendAwareDelay(3.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index 0b86fecc06..e8ec368e85 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -67,6 +67,7 @@ public struct Namespaces { public static let CloudPremiumStickers: Int32 = 13 public static let LocalRecentEmoji: Int32 = 14 public static let CloudFeaturedEmojiPacks: Int32 = 15 + public static let CloudAllPremiumStickers: Int32 = 16 } public struct CachedItemCollection { diff --git a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift index 29a034fff9..2e7db61c39 100644 --- a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift +++ b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift @@ -218,7 +218,8 @@ private final class ItemAnimationContext { } } - static let queue = Queue(name: "ItemAnimationContext", qos: .default) + static let queue0 = Queue(name: "ItemAnimationContext-0", qos: .default) + static let queue1 = Queue(name: "ItemAnimationContext-1", qos: .default) private let cache: AnimationCache private let stateUpdated: () -> Void @@ -667,17 +668,60 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer { } if !tasks.isEmpty { - ItemAnimationContext.queue.async { - var completions: [() -> Void] = [] - for task in tasks { - let complete = task.task() - completions.append(complete) + if tasks.count > 2 { + let tasks0 = Array(tasks.prefix(tasks.count / 2)) + let tasks1 = Array(tasks.suffix(tasks.count - tasks0.count)) + + var tasks0Completions: [() -> Void]? + var tasks1Completions: [() -> Void]? + + let complete: (Int, [() -> Void]) -> Void = { index, completions in + Queue.mainQueue().async { + if index == 0 { + tasks0Completions = completions + } else if index == 1 { + tasks1Completions = completions + } + if let tasks0Completions = tasks0Completions, let tasks1Completions = tasks1Completions { + for completion in tasks0Completions { + completion() + } + for completion in tasks1Completions { + completion() + } + } + } } - if !completions.isEmpty { - Queue.mainQueue().async { - for completion in completions { - completion() + ItemAnimationContext.queue0.async { + var completions: [() -> Void] = [] + for task in tasks0 { + let complete = task.task() + completions.append(complete) + } + complete(0, completions) + } + ItemAnimationContext.queue1.async { + var completions: [() -> Void] = [] + for task in tasks1 { + let complete = task.task() + completions.append(complete) + } + complete(1, completions) + } + } else { + ItemAnimationContext.queue0.async { + var completions: [() -> Void] = [] + for task in tasks { + let complete = task.task() + completions.append(complete) + } + + if !completions.isEmpty { + Queue.mainQueue().async { + for completion in completions { + completion() + } } } } diff --git a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift index 4208cf1102..c2c12fb9a4 100644 --- a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift @@ -362,7 +362,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode { let emojiItems = emojiInputData(context: context, animationCache: animationCache, animationRenderer: animationRenderer, isStandalone: false, areCustomEmojiEnabled: areCustomEmojiEnabled, chatPeerId: chatPeerId) let stickerNamespaces: [ItemCollectionId.Namespace] = [Namespaces.ItemCollection.CloudStickerPacks] - let stickerOrderedItemListCollectionIds: [Int32] = [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.CloudPremiumStickers] + let stickerOrderedItemListCollectionIds: [Int32] = [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.CloudAllPremiumStickers] struct PeerSpecificPackData: Equatable { var info: StickerPackCollectionInfo @@ -440,7 +440,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode { recentStickers = orderedView } else if orderedView.collectionId == Namespaces.OrderedItemList.CloudSavedStickers { savedStickers = orderedView - } else if orderedView.collectionId == Namespaces.OrderedItemList.CloudPremiumStickers { + } else if orderedView.collectionId == Namespaces.OrderedItemList.CloudAllPremiumStickers { cloudPremiumStickers = orderedView } } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 7c3ca46ec0..de3e088da7 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -2608,8 +2608,26 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { let replacementText = NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: emojiAttribute]) let range = currentEmojiSuggestion.position.range - + let previousText = inputText.attributedSubstring(from: range) inputText.replaceCharacters(in: range, with: replacementText) + + var replacedUpperBound = range.lowerBound + while true { + if inputText.attributedSubstring(from: NSRange(location: 0, length: replacedUpperBound)).string.hasSuffix(previousText.string) { + let replaceRange = NSRange(location: replacedUpperBound - previousText.length, length: previousText.length) + if replaceRange.location < 0 { + break + } + if inputText.attributedSubstring(from: replaceRange).string != previousText.string { + break + } + inputText.replaceCharacters(in: replaceRange, with: NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: ChatTextInputTextCustomEmojiAttribute(stickerPack: emojiAttribute.stickerPack, fileId: emojiAttribute.fileId, file: emojiAttribute.file)])) + replacedUpperBound = replaceRange.lowerBound + } else { + break + } + } + let selectionPosition = range.lowerBound + (replacementText.string as NSString).length return (ChatTextInputState(inputText: inputText, selectionRange: selectionPosition ..< selectionPosition), inputMode)