mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Various improvements
This commit is contained in:
parent
8db274cb50
commit
8e043a3a7d
28 changed files with 530 additions and 43 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<MediaId>(result.map { $0.file.fileId })
|
||||
var recentItems: [TelegramMediaFile] = []
|
||||
var recentAnimatedItems: [TelegramMediaFile] = []
|
||||
var recentItemsIds = Set<MediaId>()
|
||||
var matchingRecentItemsIds = Set<MediaId>()
|
||||
|
||||
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<MediaId>(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<Api.messages.Stickers, NoError> 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<MediaId>(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))
|
||||
|
|
|
|||
|
|
@ -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<FoundStickerSets, NoError> {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 = { }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue