diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index aa0c9bd066..a343b776ab 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -89,6 +89,7 @@ public enum AttachmentButtonType: Equatable { public protocol AttachmentContainable: ViewController { var requestAttachmentMenuExpansion: () -> Void { get set } var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void { get set } + var parentController: () -> ViewController? { get set } var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void { get set } var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void { get set } var cancelPanGesture: () -> Void { get set } @@ -560,6 +561,12 @@ public class AttachmentController: ViewController { } } } + controller.parentController = { [weak self] in + guard let self else { + return nil + } + return self.controller + } controller.updateTabBarAlpha = { [weak self, weak controller] alpha, transition in if let strongSelf = self, strongSelf.currentControllers.contains(where: { $0 === controller }) { strongSelf.panel.updateBackgroundAlpha(alpha, transition: transition) diff --git a/submodules/ComposePollUI/Sources/ComposePollScreen.swift b/submodules/ComposePollUI/Sources/ComposePollScreen.swift index e7a314753c..d7a4b5d222 100644 --- a/submodules/ComposePollUI/Sources/ComposePollScreen.swift +++ b/submodules/ComposePollUI/Sources/ComposePollScreen.swift @@ -204,9 +204,19 @@ final class ComposePollScreenComponent: Component { } } - var mappedSolution: String? + var mappedSolution: (String, [MessageTextEntity])? if self.isQuiz && self.quizAnswerTextInputState.text.length != 0 { - mappedSolution = self.quizAnswerTextInputState.text.string + var solutionTextEntities: [MessageTextEntity] = [] + for entity in generateChatInputTextEntities(self.quizAnswerTextInputState.text) { + switch entity.type { + case .CustomEmoji: + solutionTextEntities.append(entity) + default: + break + } + } + + mappedSolution = (self.quizAnswerTextInputState.text.string, solutionTextEntities) } var textEntities: [MessageTextEntity] = [] @@ -232,7 +242,7 @@ final class ComposePollScreenComponent: Component { totalVoters: nil, recentVoters: [], solution: mappedSolution.flatMap { mappedSolution in - return TelegramMediaPollResults.Solution(text: mappedSolution, entities: []) + return TelegramMediaPollResults.Solution(text: mappedSolution.0, entities: mappedSolution.1) } ), deadlineTimeout: nil, @@ -591,11 +601,21 @@ final class ComposePollScreenComponent: Component { } self.environment?.controller()?.presentInGlobalOverlay(c, with: a) }, - getNavigationController: { [weak self] in + getNavigationController: { [weak self] () -> NavigationController? in guard let self else { return nil } - return self.environment?.controller()?.navigationController as? NavigationController + guard let controller = self.environment?.controller() as? ComposePollScreen else { + return nil + } + + if let navigationController = controller.navigationController as? NavigationController { + return navigationController + } + if let parentController = controller.parentController() { + return parentController.navigationController as? NavigationController + } + return nil }, requestLayout: { [weak self] transition in guard let self else { @@ -1450,6 +1470,9 @@ public class ComposePollScreen: ViewControllerComponentContainer, AttachmentCont } public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in diff --git a/submodules/ComposePollUI/Sources/CreatePollController.swift b/submodules/ComposePollUI/Sources/CreatePollController.swift index e6b6a83b86..5fa3f3b45a 100644 --- a/submodules/ComposePollUI/Sources/CreatePollController.swift +++ b/submodules/ComposePollUI/Sources/CreatePollController.swift @@ -563,6 +563,9 @@ private final class CreatePollContext: AttachmentMediaPickerContext { public class CreatePollControllerImpl: ItemListController, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/LocationUI/Sources/LocationPickerController.swift b/submodules/LocationUI/Sources/LocationPickerController.swift index 63272c8937..d6430907db 100644 --- a/submodules/LocationUI/Sources/LocationPickerController.swift +++ b/submodules/LocationUI/Sources/LocationPickerController.swift @@ -80,6 +80,9 @@ public final class LocationPickerController: ViewController, AttachmentContainab public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/MediaPickerUI/Sources/MediaGroupsScreen.swift b/submodules/MediaPickerUI/Sources/MediaGroupsScreen.swift index ebb6d36a09..93289e5059 100644 --- a/submodules/MediaPickerUI/Sources/MediaGroupsScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaGroupsScreen.swift @@ -152,6 +152,9 @@ private func preparedTransition(from fromEntries: [MediaGroupsEntry], to toEntri public final class MediaGroupsScreen: ViewController, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index b0abae0272..cb72a77235 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -202,6 +202,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = { } public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 99fdb21828..d413abc2b8 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -2010,7 +2010,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate { })) } case let .category(value): - let resultSignal = self.context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = self.context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -2082,11 +2082,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift index b9198a4b06..70ff4f5190 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift @@ -385,6 +385,391 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt } } +func _internal_searchStickers(account: Account, category: EmojiSearchCategories.Group, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> { + if scope.isEmpty { + return .single(([], true)) + } + + var query = category.identifiers + if query == ["\u{2764}"] { + query = ["\u{2764}\u{FE0F}"] + } + + return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?, Bool, SearchStickersConfiguration) in + let isPremium = transaction.getPeer(account.peerId)?.isPremium ?? false + + var result: [FoundStickerItem] = [] + if scope.contains(.installed) { + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) { + if let item = entry.contents.get(SavedStickerItem.self) { + if case .premium = category.kind { + if item.file.isPremiumSticker { + result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations)) + } + } else { + for representation in item.stringRepresentations { + for queryItem in query { + if representation.hasPrefix(queryItem) { + result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations)) + break + } + } + } + } + } + } + + var currentItems = Set(result.map { $0.file.fileId }) + var recentItems: [TelegramMediaFile] = [] + var recentAnimatedItems: [TelegramMediaFile] = [] + var recentItemsIds = Set() + var matchingRecentItemsIds = Set() + + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentStickers) { + if let item = entry.contents.get(RecentMediaItem.self) { + let file = item.media + if file.isPremiumSticker && !isPremium { + continue + } + + if !currentItems.contains(file.fileId) { + currentItems.insert(file.fileId) + + for case let .Sticker(displayText, _, _) in file.attributes { + if case .premium = category.kind { + if file.isPremiumSticker { + matchingRecentItemsIds.insert(file.fileId) + } + } else { + for queryItem in query { + if displayText.hasPrefix(queryItem) { + matchingRecentItemsIds.insert(file.fileId) + break + } + } + } + recentItemsIds.insert(file.fileId) + if file.isAnimatedSticker || file.isVideoSticker { + recentAnimatedItems.append(file) + } else { + recentItems.append(file) + } + break + } + } + } + } + + var searchQueries: [ItemCollectionSearchQuery] = query.map { queryItem -> ItemCollectionSearchQuery in + return .exact(ValueBoxKey(queryItem)) + } + if query == ["\u{2764}"] { + searchQueries = [.any([ValueBoxKey("\u{2764}"), ValueBoxKey("\u{2764}\u{FE0F}")])] + } + + var installedItems: [FoundStickerItem] = [] + var installedAnimatedItems: [FoundStickerItem] = [] + var installedPremiumItems: [FoundStickerItem] = [] + + if case .premium = category.kind { + for (_, _, items) in transaction.getCollectionsItems(namespace: Namespaces.ItemCollection.CloudStickerPacks) { + for item in items { + guard let item = item as? StickerPackItem else { + continue + } + if item.file.isPremiumSticker { + if currentItems.contains(item.file.fileId) { + continue + } + currentItems.insert(item.file.fileId) + + if !recentItemsIds.contains(item.file.fileId) { + if item.file.isPremiumSticker { + installedPremiumItems.append(FoundStickerItem(file: item.file, stringRepresentations: [])) + } else if item.file.isAnimatedSticker || item.file.isVideoSticker { + installedAnimatedItems.append(FoundStickerItem(file: item.file, stringRepresentations: [])) + } else { + installedItems.append(FoundStickerItem(file: item.file, stringRepresentations: [])) + } + } else { + matchingRecentItemsIds.insert(item.file.fileId) + if item.file.isAnimatedSticker || item.file.isVideoSticker { + recentAnimatedItems.append(item.file) + } else { + recentItems.append(item.file) + } + } + } + } + } + + for item in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudAllPremiumStickers) { + guard let item = item.contents.get(RecentMediaItem.self) else { + continue + } + if currentItems.contains(item.media.fileId) { + continue + } + currentItems.insert(item.media.fileId) + + if !recentItemsIds.contains(item.media.fileId) { + if item.media.isPremiumSticker { + installedPremiumItems.append(FoundStickerItem(file: item.media, stringRepresentations: [])) + } else if item.media.isAnimatedSticker || item.media.isVideoSticker { + installedAnimatedItems.append(FoundStickerItem(file: item.media, stringRepresentations: [])) + } else { + installedItems.append(FoundStickerItem(file: item.media, stringRepresentations: [])) + } + } else { + matchingRecentItemsIds.insert(item.media.fileId) + if item.media.isAnimatedSticker || item.media.isVideoSticker { + recentAnimatedItems.append(item.media) + } else { + recentItems.append(item.media) + } + } + } + } else { + for searchQuery in searchQueries { + for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, query: searchQuery) { + if let item = item as? StickerPackItem { + if !currentItems.contains(item.file.fileId) { + currentItems.insert(item.file.fileId) + + let stringRepresentations = item.getStringRepresentationsOfIndexKeys() + if !recentItemsIds.contains(item.file.fileId) { + if item.file.isPremiumSticker { + installedPremiumItems.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) + } else if item.file.isAnimatedSticker || item.file.isVideoSticker { + installedAnimatedItems.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) + } else { + installedItems.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) + } + } else { + matchingRecentItemsIds.insert(item.file.fileId) + if item.file.isAnimatedSticker || item.file.isVideoSticker { + recentAnimatedItems.append(item.file) + } else { + recentItems.append(item.file) + } + } + } + } + } + } + } + + for file in recentAnimatedItems { + if file.isPremiumSticker && !isPremium { + continue + } + if matchingRecentItemsIds.contains(file.fileId) { + result.append(FoundStickerItem(file: file, stringRepresentations: query)) + } + } + + for file in recentItems { + if file.isPremiumSticker && !isPremium { + continue + } + if matchingRecentItemsIds.contains(file.fileId) { + result.append(FoundStickerItem(file: file, stringRepresentations: query)) + } + } + + result.append(contentsOf: installedPremiumItems) + result.append(contentsOf: installedAnimatedItems) + result.append(contentsOf: installedItems) + } + + var cached: CachedStickerQueryResult? + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue + let searchStickersConfiguration = SearchStickersConfiguration.with(appConfiguration: appConfiguration) + + if case .premium = category.kind { + } else { + let combinedQuery = query.joined(separator: "") + cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(combinedQuery)))?.get(CachedStickerQueryResult.self) + + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + + if let currentCached = cached, currentTime > currentCached.timestamp + searchStickersConfiguration.cacheTimeout { + cached = nil + } + } + + return (result, cached, isPremium, searchStickersConfiguration) + } + |> mapToSignal { localItems, cached, isPremium, searchStickersConfiguration -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in + if !scope.contains(.remote) { + return .single((localItems, true)) + } + if case .premium = category.kind { + return .single((localItems, true)) + } + + var tempResult: [FoundStickerItem] = [] + let currentItemIds = Set(localItems.map { $0.file.fileId }) + + var premiumItems: [FoundStickerItem] = [] + var otherItems: [FoundStickerItem] = [] + + for item in localItems { + if item.file.isPremiumSticker { + premiumItems.append(item) + } else { + otherItems.append(item) + } + } + + if let cached = cached { + var cachedItems: [FoundStickerItem] = [] + var cachedAnimatedItems: [FoundStickerItem] = [] + var cachedPremiumItems: [FoundStickerItem] = [] + + for file in cached.items { + if !currentItemIds.contains(file.fileId) { + if file.isPremiumSticker { + cachedPremiumItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } else if file.isAnimatedSticker || file.isVideoSticker { + cachedAnimatedItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } else { + cachedItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } + } + } + + otherItems.append(contentsOf: cachedAnimatedItems) + otherItems.append(contentsOf: cachedItems) + + let allPremiumItems = premiumItems + cachedPremiumItems + let allOtherItems = otherItems + cachedAnimatedItems + cachedItems + + if isPremium { + let batchCount = Int(searchStickersConfiguration.normalStickersPerPremiumCount) + if batchCount == 0 { + tempResult.append(contentsOf: allPremiumItems) + tempResult.append(contentsOf: allOtherItems) + } else { + if allPremiumItems.isEmpty { + tempResult.append(contentsOf: allOtherItems) + } else { + var i = 0 + for premiumItem in allPremiumItems { + if i < allOtherItems.count { + for j in i ..< min(i + batchCount, allOtherItems.count) { + tempResult.append(allOtherItems[j]) + } + i += batchCount + } + tempResult.append(premiumItem) + } + if i < allOtherItems.count { + for j in i ..< allOtherItems.count { + tempResult.append(allOtherItems[j]) + } + } + } + } + } else { + tempResult.append(contentsOf: allOtherItems) + tempResult.append(contentsOf: allPremiumItems.prefix(max(0, Int(searchStickersConfiguration.premiumStickersCount)))) + } + } + + let remote = account.network.request(Api.functions.messages.getStickers(emoticon: query.joined(separator: ""), hash: cached?.hash ?? 0)) + |> `catch` { _ -> Signal in + return .single(.stickersNotModified) + } + |> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in + return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in + switch result { + case let .stickers(hash, stickers): + var result: [FoundStickerItem] = [] + let currentItemIds = Set(localItems.map { $0.file.fileId }) + + var premiumItems: [FoundStickerItem] = [] + var otherItems: [FoundStickerItem] = [] + + for item in localItems { + if item.file.isPremiumSticker { + premiumItems.append(item) + } else { + otherItems.append(item) + } + } + + var foundItems: [FoundStickerItem] = [] + var foundAnimatedItems: [FoundStickerItem] = [] + var foundPremiumItems: [FoundStickerItem] = [] + + var files: [TelegramMediaFile] = [] + for sticker in stickers { + if let file = telegramMediaFileFromApiDocument(sticker), let id = file.id { + files.append(file) + if !currentItemIds.contains(id) { + if file.isPremiumSticker { + foundPremiumItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } else if file.isAnimatedSticker || file.isVideoSticker { + foundAnimatedItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } else { + foundItems.append(FoundStickerItem(file: file, stringRepresentations: [])) + } + } + } + } + + let allPremiumItems = premiumItems + foundPremiumItems + let allOtherItems = otherItems + foundAnimatedItems + foundItems + + if isPremium { + let batchCount = Int(searchStickersConfiguration.normalStickersPerPremiumCount) + if batchCount == 0 { + result.append(contentsOf: allPremiumItems) + result.append(contentsOf: allOtherItems) + } else { + if allPremiumItems.isEmpty { + result.append(contentsOf: allOtherItems) + } else { + var i = 0 + for premiumItem in allPremiumItems { + if i < allOtherItems.count { + for j in i ..< min(i + batchCount, allOtherItems.count) { + result.append(allOtherItems[j]) + } + i += batchCount + } + result.append(premiumItem) + } + if i < allOtherItems.count { + for j in i ..< allOtherItems.count { + result.append(allOtherItems[j]) + } + } + } + } + } else { + result.append(contentsOf: allOtherItems) + result.append(contentsOf: allPremiumItems.prefix(max(0, Int(searchStickersConfiguration.premiumStickersCount)))) + } + + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query.joined(separator: ""))), entry: entry) + } + + return (result, true) + case .stickersNotModified: + break + } + return (tempResult, true) + } + } + return .single((tempResult, false)) + |> then(remote) + } +} + func _internal_searchEmoji(account: Account, query: [String], scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> { if scope.isEmpty { return .single(([], true)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/TelegramEngineStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/TelegramEngineStickers.swift index a29f884883..42ee3b92fa 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/TelegramEngineStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/TelegramEngineStickers.swift @@ -33,6 +33,10 @@ public extension TelegramEngine { public func searchStickers(query: [String], scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> { return _internal_searchStickers(account: self.account, query: query, scope: scope) } + + public func searchStickers(category: EmojiSearchCategories.Group, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> { + return _internal_searchStickers(account: self.account, category: category, scope: scope) + } public func searchStickerSetsRemotely(query: String) -> Signal { return _internal_searchStickerSetsRemotely(network: self.account.network, query: query) @@ -286,6 +290,13 @@ public extension TelegramEngine { } } + public func searchEmoji(category: EmojiSearchCategories.Group) -> Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError> { + return _internal_searchEmoji(account: self.account, query: category.identifiers) + |> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in + return (items.map(\.file), isFinalResult) + } + } + public func addRecentlyUsedSticker(fileReference: FileMediaReference) { let _ = self.account.postbox.transaction({ transaction -> Void in TelegramCore.addRecentlyUsedSticker(transaction: transaction, fileReference: fileReference) diff --git a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift index 123dfeb747..563cd08d21 100644 --- a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift +++ b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift @@ -483,7 +483,7 @@ final class AvatarEditorScreenComponent: Component { })) } case let .category(value): - let resultSignal = context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -557,11 +557,11 @@ final class AvatarEditorScreenComponent: Component { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramUI/Components/Chat/ChatOverscrollControl/Sources/ChatOverscrollControl.swift b/submodules/TelegramUI/Components/Chat/ChatOverscrollControl/Sources/ChatOverscrollControl.swift index b505081b99..0c36513a21 100644 --- a/submodules/TelegramUI/Components/Chat/ChatOverscrollControl/Sources/ChatOverscrollControl.swift +++ b/submodules/TelegramUI/Components/Chat/ChatOverscrollControl/Sources/ChatOverscrollControl.swift @@ -752,6 +752,7 @@ final class OverscrollContentsComponent: Component { let foregroundColor: UIColor let peer: EnginePeer? let threadData: ChatOverscrollThreadData? + let isForumThread: Bool let unreadCount: Int let location: TelegramEngine.NextUnreadChannelLocation let expandOffset: CGFloat @@ -766,6 +767,7 @@ final class OverscrollContentsComponent: Component { foregroundColor: UIColor, peer: EnginePeer?, threadData: ChatOverscrollThreadData?, + isForumThread: Bool, unreadCount: Int, location: TelegramEngine.NextUnreadChannelLocation, expandOffset: CGFloat, @@ -779,6 +781,7 @@ final class OverscrollContentsComponent: Component { self.foregroundColor = foregroundColor self.peer = peer self.threadData = threadData + self.isForumThread = isForumThread self.unreadCount = unreadCount self.location = location self.expandOffset = expandOffset @@ -804,6 +807,9 @@ final class OverscrollContentsComponent: Component { if lhs.threadData != rhs.threadData { return false } + if lhs.isForumThread != rhs.isForumThread { + return false + } if lhs.unreadCount != rhs.unreadCount { return false } @@ -965,6 +971,9 @@ final class OverscrollContentsComponent: Component { titleText = threadData.data.info.title } else if let peer = component.peer { titleText = peer.compactDisplayTitle + } else if component.isForumThread { + //TODO:localize + titleText = "You have no unread topics" } else { titleText = component.context.sharedContext.currentPresentationData.with({ $0 }).strings.Chat_NavigationNoChannels } @@ -1083,6 +1092,7 @@ public final class ChatOverscrollControl: CombinedComponent { let foregroundColor: UIColor let peer: EnginePeer? let threadData: ChatOverscrollThreadData? + let isForumThread: Bool let unreadCount: Int let location: TelegramEngine.NextUnreadChannelLocation let context: AccountContext @@ -1097,6 +1107,7 @@ public final class ChatOverscrollControl: CombinedComponent { foregroundColor: UIColor, peer: EnginePeer?, threadData: ChatOverscrollThreadData?, + isForumThread: Bool, unreadCount: Int, location: TelegramEngine.NextUnreadChannelLocation, context: AccountContext, @@ -1110,6 +1121,7 @@ public final class ChatOverscrollControl: CombinedComponent { self.foregroundColor = foregroundColor self.peer = peer self.threadData = threadData + self.isForumThread = isForumThread self.unreadCount = unreadCount self.location = location self.context = context @@ -1133,6 +1145,9 @@ public final class ChatOverscrollControl: CombinedComponent { if lhs.threadData != rhs.threadData { return false } + if lhs.isForumThread != rhs.isForumThread { + return false + } if lhs.unreadCount != rhs.unreadCount { return false } @@ -1171,6 +1186,7 @@ public final class ChatOverscrollControl: CombinedComponent { foregroundColor: context.component.foregroundColor, peer: context.component.peer, threadData: context.component.threadData, + isForumThread: context.component.isForumThread, unreadCount: context.component.unreadCount, location: context.component.location, expandOffset: context.component.expandDistance, diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 69ed4bd50d..81555f268c 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -697,7 +697,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } premiumToastCounter += 1 - let suggestSavedMessages = premiumToastCounter % 2 == 0 + var suggestSavedMessages = premiumToastCounter % 2 == 0 + if chatPeerId == nil { + suggestSavedMessages = false + } let text: String let actionTitle: String if suggestSavedMessages { @@ -1091,7 +1094,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { })) } case let .category(value): - let resultSignal = self.context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = self.context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -1105,7 +1108,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { let item = EmojiPagerContentComponent.Item( animationData: animationData, content: .animation(animationData), - itemFile: itemFile, subgroupId: nil, + itemFile: itemFile, + subgroupId: nil, icon: .none, tintMode: animationData.isTemplate ? .primary : .none ) @@ -1162,10 +1166,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } @@ -1434,7 +1438,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { strongSelf.stickerSearchDisposable.set(nil) strongSelf.stickerSearchStateValue = EmojiSearchState(result: nil, isSearching: false) case let .category(value): - let resultSignal = strongSelf.context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote]) + let resultSignal = strongSelf.context.engine.stickers.searchStickers(category: value, scope: [.installed, .remote]) |> mapToSignal { files -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -1506,10 +1510,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift index a668a5f97d..5fca0d36fc 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift @@ -615,7 +615,7 @@ public final class EmojiStatusSelectionController: ViewController { })) } case let .category(value): - let resultSignal = self.context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = self.context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -687,11 +687,11 @@ public final class EmojiStatusSelectionController: ViewController { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index f71777f833..30d4ec87a1 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -1744,7 +1744,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate { private var textField: EmojiSearchTextField? private var tapRecognizer: UITapGestureRecognizer? - private(set) var currentPresetSearchTerm: [String]? + private(set) var currentPresetSearchTerm: EmojiSearchCategories.Group? private var params: Params? @@ -2570,7 +2570,7 @@ public final class EmojiPagerContentComponent: Component { public enum SearchQuery: Equatable { case text(value: String, language: String) - case category(value: [String]) + case category(value: EmojiSearchCategories.Group) } public enum ItemContent: Equatable { diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift index 2ab27b0967..e8fb0bd8c9 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift @@ -319,7 +319,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode })) } case let .category(value): - let resultSignal = self.context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = self.context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -333,7 +333,8 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode let item = EmojiPagerContentComponent.Item( animationData: animationData, content: .animation(animationData), - itemFile: itemFile, subgroupId: nil, + itemFile: itemFile, + subgroupId: nil, icon: .none, tintMode: animationData.isTemplate ? .primary : .none ) @@ -393,11 +394,11 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: false), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: false), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchSearchBarComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchSearchBarComponent.swift index d3b6f06900..93c8f1e164 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchSearchBarComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchSearchBarComponent.swift @@ -104,7 +104,7 @@ final class EmojiSearchSearchBarComponent: Component { let useOpaqueTheme: Bool let textInputState: TextInputState let categories: EmojiSearchCategories? - let searchTermUpdated: ([String]?) -> Void + let searchTermUpdated: (EmojiSearchCategories.Group?) -> Void let activateTextInput: () -> Void init( @@ -115,7 +115,7 @@ final class EmojiSearchSearchBarComponent: Component { useOpaqueTheme: Bool, textInputState: TextInputState, categories: EmojiSearchCategories?, - searchTermUpdated: @escaping ([String]?) -> Void, + searchTermUpdated: @escaping (EmojiSearchCategories.Group?) -> Void, activateTextInput: @escaping () -> Void ) { self.context = context @@ -366,7 +366,7 @@ final class EmojiSearchSearchBarComponent: Component { self.componentState?.updated(transition: .easeInOut(duration: 0.2)) if let _ = self.selectedItem, let categories = component.categories, let group = categories.groups.first(where: { $0.id == itemId }) { - component.searchTermUpdated(group.identifiers) + component.searchTermUpdated(group) if let itemComponentView = itemView.view.view { var offset = self.scrollView.contentOffset.x diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift index c601dbf308..c4943a46a7 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift @@ -1081,7 +1081,7 @@ public final class GifPagerContentComponent: Component { case .text: break case let .category(value): - component.inputInteraction.updateSearchQuery(value) + component.inputInteraction.updateSearchQuery(value.identifiers) } }) self.visibleSearchHeader = visibleSearchHeader diff --git a/submodules/TelegramUI/Components/PremiumGiftAttachmentScreen/Sources/PremiumGiftAttachmentScreen.swift b/submodules/TelegramUI/Components/PremiumGiftAttachmentScreen/Sources/PremiumGiftAttachmentScreen.swift index fbcd865a8f..6232f869d9 100644 --- a/submodules/TelegramUI/Components/PremiumGiftAttachmentScreen/Sources/PremiumGiftAttachmentScreen.swift +++ b/submodules/TelegramUI/Components/PremiumGiftAttachmentScreen/Sources/PremiumGiftAttachmentScreen.swift @@ -11,6 +11,9 @@ import AttachmentUI public class PremiumGiftAttachmentScreen: PremiumGiftScreen, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var cancelPanGesture: () -> Void = { } public var isContainerPanning: () -> Bool = { return false } public var isContainerExpanded: () -> Bool = { return false } diff --git a/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift index 81fb4a55ef..110d7b1671 100644 --- a/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift @@ -1303,6 +1303,9 @@ public final class QuickReplySetupScreen: ViewControllerComponentContainer, Atta } public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in diff --git a/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/BusinessIntroSetupScreen.swift b/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/BusinessIntroSetupScreen.swift index 047ec57524..b06da137cc 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/BusinessIntroSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessIntroSetupScreen/Sources/BusinessIntroSetupScreen.swift @@ -518,7 +518,7 @@ final class BusinessIntroSetupScreenComponent: Component { })) } case let .category(value): - let resultSignal = component.context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote]) + let resultSignal = component.context.engine.stickers.searchStickers(category: value, scope: [.installed, .remote]) |> mapToSignal { files -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -589,13 +589,13 @@ final class BusinessIntroSetupScreenComponent: Component { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) if !self.isUpdating { self.state?.updated(transition: .immediate) } return } - self.stickerSearchState = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.stickerSearchState = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 if !self.isUpdating { self.state?.updated(transition: .immediate) diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeColorsGridController.swift b/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeColorsGridController.swift index 69902150f8..5892427c04 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeColorsGridController.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeColorsGridController.swift @@ -337,6 +337,9 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/TelegramUI/Components/StickerPickerScreen/Sources/StickerPickerScreen.swift b/submodules/TelegramUI/Components/StickerPickerScreen/Sources/StickerPickerScreen.swift index f110a6643d..851c034270 100644 --- a/submodules/TelegramUI/Components/StickerPickerScreen/Sources/StickerPickerScreen.swift +++ b/submodules/TelegramUI/Components/StickerPickerScreen/Sources/StickerPickerScreen.swift @@ -1156,7 +1156,7 @@ public class StickerPickerScreen: ViewController { })) } case let .category(value): - let resultSignal = context.engine.stickers.searchEmoji(emojiString: value) + let resultSignal = context.engine.stickers.searchEmoji(category: value) |> mapToSignal { files, isFinalResult -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -1227,10 +1227,10 @@ public class StickerPickerScreen: ViewController { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } @@ -1442,7 +1442,7 @@ public class StickerPickerScreen: ViewController { strongSelf.stickerSearchDisposable.set(nil) strongSelf.stickerSearchStateValue = EmojiSearchState(result: nil, isSearching: false) case let .category(value): - let resultSignal = context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote]) + let resultSignal = context.engine.stickers.searchStickers(category: value, scope: [.installed, .remote]) |> mapToSignal { files -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in var items: [EmojiPagerContentComponent.Item] = [] @@ -1513,10 +1513,10 @@ public class StickerPickerScreen: ViewController { fillWithLoadingPlaceholders: true, items: [] ) - ], id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + ], id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) return } - strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false) + strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value.id), version: version, isPreset: true), isSearching: false) version += 1 })) } diff --git a/submodules/TelegramUI/Sources/AttachmentFileController.swift b/submodules/TelegramUI/Sources/AttachmentFileController.swift index 8c56d16af5..c1c1126a1c 100644 --- a/submodules/TelegramUI/Sources/AttachmentFileController.swift +++ b/submodules/TelegramUI/Sources/AttachmentFileController.swift @@ -196,6 +196,9 @@ private final class AttachmentFileContext: AttachmentMediaPickerContext { class AttachmentFileControllerImpl: ItemListController, AttachmentFileController, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = {} public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index d8f1f5d5d0..fb06ed7c9d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -8450,7 +8450,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .entities(text: solution.text, entities: solution.entities), icon: .animation(name: "anim_infotip", delay: 0.2, tintColor: nil), location: .top, shouldDismissOnTouch: { point, _ in + let tooltipScreen = TooltipScreen(context: self.context, account: self.context.account, sharedContext: self.context.sharedContext, text: .entities(text: solution.text, entities: solution.entities), icon: .animation(name: "anim_infotip", delay: 0.2, tintColor: nil), location: .top, shouldDismissOnTouch: { point, _ in return .ignore }, openActiveTextItem: { [weak self] item, action in guard let strongSelf = self else { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 64e7814da4..38bfd4aa2a 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2298,6 +2298,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto data: threadData.data ) }, + isForumThread: self.chatLocation.threadId != nil, unreadCount: self.nextChannelToRead?.unreadCount ?? 0, location: self.nextChannelToRead?.location ?? .same, context: self.context, diff --git a/submodules/TelegramUI/Sources/ContactSelectionController.swift b/submodules/TelegramUI/Sources/ContactSelectionController.swift index a4e96a6a95..65cf9921a3 100644 --- a/submodules/TelegramUI/Sources/ContactSelectionController.swift +++ b/submodules/TelegramUI/Sources/ContactSelectionController.swift @@ -78,6 +78,9 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController var requestAttachmentMenuExpansion: () -> Void = {} var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } var cancelPanGesture: () -> Void = { } diff --git a/submodules/TooltipUI/Sources/TooltipScreen.swift b/submodules/TooltipUI/Sources/TooltipScreen.swift index 7d0975080a..330aa3ea3b 100644 --- a/submodules/TooltipUI/Sources/TooltipScreen.swift +++ b/submodules/TooltipUI/Sources/TooltipScreen.swift @@ -601,7 +601,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode { } let textSize: CGSize - if case .attributedString = self.text, let context = self.context { + + var isTextWithEntities = false + switch self.text { + case .attributedString, .entities: + isTextWithEntities = true + default: + break + } + + if isTextWithEntities, let context = self.context { textSize = self.textView.update( transition: .immediate, component: AnyComponent(MultilineTextWithEntitiesComponent( diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 6b481b5d66..fba52e1af8 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -258,6 +258,9 @@ public func generateWebAppThemeParams(_ presentationTheme: PresentationTheme) -> public final class WebAppController: ViewController, AttachmentContainable { public var requestAttachmentMenuExpansion: () -> Void = { } public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in } + public var parentController: () -> ViewController? = { + return nil + } public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in } public var updateTabBarVisibility: (Bool, ContainedViewLayoutTransition) -> Void = { _, _ in } public var cancelPanGesture: () -> Void = { }