Global search

This commit is contained in:
Isaac 2025-07-27 15:01:53 +02:00
parent b8ac955792
commit e315e6da6e
20 changed files with 265 additions and 105 deletions

View File

@ -157,6 +157,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
private let sharedOpenStoryDisposable = MetaDisposable()
private var recentAppsDisposable: Disposable?
private var refreshedGlobalPostSearchStateDisposable: Disposable?
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
var initialFilter = initialFilter
@ -531,6 +532,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
self.recentAppsDisposable = context.engine.peers.managedUpdatedRecentApps().startStrict()
self.refreshedGlobalPostSearchStateDisposable = context.engine.messages.refreshGlobalPostSearchState().startStrict()
self._ready.set(self.paneContainerNode.isReady.get()
|> map { _ in Void() })
@ -543,6 +545,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
self.shareStatusDisposable?.dispose()
self.sharedOpenStoryDisposable.dispose()
self.recentAppsDisposable?.dispose()
self.refreshedGlobalPostSearchStateDisposable?.dispose()
self.copyProtectionTooltipController?.dismiss()
}

View File

@ -1298,11 +1298,10 @@ public struct ChatListSearchContainerTransition {
public let isLoading: Bool
public let query: String?
public let approvedGlobalPostQueryState: ApprovedGlobalPostQueryState?
public let remainingGlobalSearches: Int
public let globalSearchUnlockTimestamp: Int32?
public let globalSearchStateValue: TelegramGlobalPostSearchState?
public var animated: Bool
public init(deletions: [ListViewDeleteItem], insertions: [ListViewInsertItem], updates: [ListViewUpdateItem], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, query: String?, approvedGlobalPostQueryState: ApprovedGlobalPostQueryState?, remainingGlobalSearches: Int, globalSearchUnlockTimestamp: Int32?, animated: Bool) {
public init(deletions: [ListViewDeleteItem], insertions: [ListViewInsertItem], updates: [ListViewUpdateItem], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, query: String?, approvedGlobalPostQueryState: ApprovedGlobalPostQueryState?, globalSearchStateValue: TelegramGlobalPostSearchState?, animated: Bool) {
self.deletions = deletions
self.insertions = insertions
self.updates = updates
@ -1310,8 +1309,7 @@ public struct ChatListSearchContainerTransition {
self.isEmpty = isEmpty
self.isLoading = isLoading
self.approvedGlobalPostQueryState = approvedGlobalPostQueryState
self.remainingGlobalSearches = remainingGlobalSearches
self.globalSearchUnlockTimestamp = globalSearchUnlockTimestamp
self.globalSearchStateValue = globalSearchStateValue
self.query = query
self.animated = animated
}
@ -1376,8 +1374,7 @@ public func chatListSearchContainerPreparedTransition(
searchPeer: @escaping (EnginePeer) -> Void,
searchQuery: String?,
approvedGlobalPostQueryState: ApprovedGlobalPostQueryState?,
remainingGlobalSearches: Int,
globalSearchUnlockTimestamp: Int32?,
globalSearchStateValue: TelegramGlobalPostSearchState?,
searchOptions: ChatListSearchOptions?,
messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?,
openClearRecentlyDownloaded: @escaping () -> Void,
@ -1393,7 +1390,7 @@ public func chatListSearchContainerPreparedTransition(
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused, openStories: openStories, openPublicPosts: openPublicPosts, openMessagesFilter: openMessagesFilter, switchMessagesFilter: switchMessagesFilter), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused, openStories: openStories, openPublicPosts: openPublicPosts, openMessagesFilter: openMessagesFilter, switchMessagesFilter: switchMessagesFilter), directionHint: nil) }
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, isLoading: isLoading, query: searchQuery, approvedGlobalPostQueryState: approvedGlobalPostQueryState, remainingGlobalSearches: remainingGlobalSearches, globalSearchUnlockTimestamp: globalSearchUnlockTimestamp, animated: animated)
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, isLoading: isLoading, query: searchQuery, approvedGlobalPostQueryState: approvedGlobalPostQueryState, globalSearchStateValue: globalSearchStateValue, animated: animated)
}
private struct ChatListSearchListPaneNodeState: Equatable {
@ -1620,16 +1617,6 @@ public struct ApprovedGlobalPostQueryState: Equatable {
}
}
struct TelegramGlobalPostSearchState: Equatable {
var remainingSearches: Int
var unlockTimestamp: Int32?
init(remainingSearches: Int, unlockTimestamp: Int32?) {
self.remainingSearches = remainingSearches
self.unlockTimestamp = unlockTimestamp
}
}
final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
private let context: AccountContext
private let animationCache: AnimationCache
@ -1676,7 +1663,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
private var searchQueryValue: String?
private var searchOptionsValue: ChatListSearchOptions?
private var approvedGlobalPostQueryStateValue: ApprovedGlobalPostQueryState?
private var globalPostSearchStateValue: TelegramGlobalPostSearchState
private var globalPostSearchStateValue: TelegramGlobalPostSearchState?
private var globalPostSearchUnlockTimer: Foundation.Timer?
private var isPremium: Bool = false
@ -1737,7 +1724,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
private let searchScopePromise = ValuePromise<TelegramSearchPeersScope>(.everywhere)
private let approvedGlobalPostQueryState = ValuePromise<ApprovedGlobalPostQueryState?>(nil, ignoreRepeated: true)
private let globalPostSearchState = Promise<TelegramGlobalPostSearchState>()
private let globalPostSearchState = Promise<TelegramGlobalPostSearchState?>()
private var refreshGlobalPostSearchStateDisposable: Disposable?
init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, interaction: ChatListSearchInteraction, key: ChatListSearchPaneKey, peersFilter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, searchQuery: Signal<String?, NoError>, searchOptions: Signal<ChatListSearchOptions?, NoError>, navigationController: NavigationController?, parentController: ViewController?, globalPeerSearchContext: GlobalPeerSearchContext?) {
self.context = context
@ -1752,8 +1741,6 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
let globalPeerSearchContext = globalPeerSearchContext ?? GlobalPeerSearchContext()
self.globalPeerSearchContext = globalPeerSearchContext
self.globalPostSearchStateValue = TelegramGlobalPostSearchState(remainingSearches: 2, unlockTimestamp: nil)
var peersFilter = peersFilter
if case .forum = location {
@ -2056,6 +2043,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
let globalPostSearchStateType = self.globalPostSearchState.get()
|> map { state -> Bool in
guard let state else {
return false
}
return state.unlockTimestamp != nil
}
|> distinctUntilChanged
@ -3624,7 +3614,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
listInteraction?.searchTextHighightState = query
chatListInteraction?.searchTextHighightState = query
})
self.globalPostSearchState.set(.single(self.globalPostSearchStateValue))
self.globalPostSearchState.set(context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Messages.GlobalPostSearchState()
))
self.approvedSearchQueryDisposable = (combineLatest(queue: .mainQueue(), self.approvedGlobalPostQueryState.get(), self.globalPostSearchState.get(), isPremium)
|> deliverOnMainQueue).startStrict(next: { [weak self] approvedGlobalPostQueryState, globalPostSearchState, isPremium in
guard let self else {
@ -3634,27 +3626,25 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
self.globalPostSearchStateValue = globalPostSearchState
self.isPremium = isPremium
if globalPostSearchState.unlockTimestamp != nil {
if let globalPostSearchState, globalPostSearchState.unlockTimestamp != nil {
if self.globalPostSearchUnlockTimer == nil {
self.globalPostSearchUnlockTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] _ in
guard let self else {
return
}
if let unlockTimestamp = self.globalPostSearchStateValue.unlockTimestamp {
if let unlockTimestamp = self.globalPostSearchStateValue?.unlockTimestamp {
var remainingTime: Int32 = unlockTimestamp - Int32(Date().timeIntervalSince1970)
remainingTime = max(0, remainingTime)
if remainingTime == 0 {
if let globalPostSearchUnlockTimer = self.globalPostSearchUnlockTimer {
self.globalPostSearchUnlockTimer = nil
globalPostSearchUnlockTimer.invalidate()
if self.refreshGlobalPostSearchStateDisposable == nil {
self.refreshGlobalPostSearchStateDisposable = self.context.engine.messages.refreshGlobalPostSearchState().start(completed: { [weak self] in
guard let self else {
return
}
self.refreshGlobalPostSearchStateDisposable = nil
})
}
//TODO:localize
var globalPostSearchState = self.globalPostSearchStateValue
globalPostSearchState.unlockTimestamp = nil
globalPostSearchState.remainingSearches = 2
self.globalPostSearchState.set(.single(globalPostSearchState))
}
}
})
@ -3816,8 +3806,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
},
searchQuery: strongSelf.searchQueryValue,
approvedGlobalPostQueryState: strongSelf.approvedGlobalPostQueryStateValue,
remainingGlobalSearches: strongSelf.globalPostSearchStateValue.remainingSearches,
globalSearchUnlockTimestamp: strongSelf.globalPostSearchStateValue.unlockTimestamp,
globalSearchStateValue: strongSelf.globalPostSearchStateValue,
searchOptions: strongSelf.searchOptionsValue, messageContextAction: { message, node, rect, gesture, paneKey, downloadResource in
interaction.messageContextAction(message, node, rect, gesture, paneKey, downloadResource)
}, openClearRecentlyDownloaded: {
@ -4694,6 +4683,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
self.approvedSearchQueryDisposable?.dispose()
self.searchOptionsDisposable?.dispose()
self.globalPostSearchUnlockTimer?.invalidate()
self.refreshGlobalPostSearchStateDisposable?.dispose()
}
override func didLoad() {
@ -4767,6 +4757,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) {
let hadValidLayout = self.currentParams != nil
let layoutChanged = self.currentParams?.size != size || self.currentParams?.sideInset != sideInset || self.currentParams?.bottomInset != bottomInset || self.currentParams?.visibleHeight != visibleHeight
self.currentParams = (size, sideInset, bottomInset, visibleHeight, presentationData)
var topPanelHeight: CGFloat = 0.0
@ -5128,8 +5119,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if let searchQueryValue = self.searchQueryValue, !searchQueryValue.isEmpty, self.approvedGlobalPostQueryStateValue?.query != searchQueryValue {
var price: Int?
var globalPostSearchStateValue = self.globalPostSearchStateValue
if globalPostSearchStateValue.remainingSearches == 0 {
if let globalPostSearchStateValue = self.globalPostSearchStateValue, globalPostSearchStateValue.remainingFreeSearches == 0 {
//TODO:localize
price = 10
}
@ -5139,15 +5129,6 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
price: price
))
if globalPostSearchStateValue.remainingSearches > 0 {
globalPostSearchStateValue.remainingSearches -= 1
if globalPostSearchStateValue.remainingSearches == 0 {
globalPostSearchStateValue.unlockTimestamp = Int32(Date().timeIntervalSince1970) + 30
}
}
self.globalPostSearchState.set(.single(globalPostSearchStateValue))
if let price {
//TODO:localize
if let controller = self.navigationController?.topViewController as? ViewController {
@ -5230,7 +5211,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
emptyTitleY = emptyAnimationY
}
let textTransition = ContainedViewLayoutTransition.immediate
let textTransition: ContainedViewLayoutTransition = layoutChanged ? transition : .immediate
textTransition.updateFrame(node: self.emptyResultsAnimationNode, frame: CGRect(origin: CGPoint(x: sideInset + padding + (size.width - sideInset * 2.0 - padding * 2.0 - self.emptyResultsAnimationSize.width) / 2.0, y: emptyAnimationY), size: self.emptyResultsAnimationSize))
textTransition.updateFrame(node: self.emptyResultsTitleNode, frame: CGRect(origin: CGPoint(x: sideInset + padding + (size.width - sideInset * 2.0 - padding * 2.0 - emptyTitleSize.width) / 2.0, y: emptyTitleY), size: emptyTitleSize))
textTransition.updateFrame(node: self.emptyResultsTextNode, frame: CGRect(origin: CGPoint(x: sideInset + padding + (size.width - sideInset * 2.0 - padding * 2.0 - emptyTextSize.width) / 2.0, y: emptyTitleY + emptyTitleSize.height + emptyTextSpacing), size: emptyTextSize))
@ -5240,20 +5221,24 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if let emptyButtonView = self.emptyResultsButton?.view, let emptyButtonSize {
nextY += emptyButtonSpacing
var emptyButtonTransition = textTransition
if emptyButtonView.superview == nil {
emptyButtonTransition = .immediate
self.view.insertSubview(emptyButtonView, aboveSubview: self.emptyResultsTextNode.view)
}
emptyButtonView.frame = CGRect(origin: CGPoint(x: floor((size.width - emptyButtonSize.width) * 0.5), y: nextY), size: emptyButtonSize)
emptyButtonTransition.updateFrame(view: emptyButtonView, frame: CGRect(origin: CGPoint(x: floor((size.width - emptyButtonSize.width) * 0.5), y: nextY), size: emptyButtonSize))
nextY += emptyButtonSize.height
}
if let emptyButtonSubtitleView = self.emptyResultsButtonSubtitle?.view, let emptyButtonSubtitleSize {
nextY += emptyButtonSubtitleSpacing
var emptyButtonSubtitleTransition = textTransition
if emptyButtonSubtitleView.superview == nil {
emptyButtonSubtitleTransition = .immediate
self.view.insertSubview(emptyButtonSubtitleView, aboveSubview: self.emptyResultsTextNode.view)
}
emptyButtonSubtitleView.frame = CGRect(origin: CGPoint(x: floor((size.width - emptyButtonSubtitleSize.width) * 0.5), y: nextY), size: emptyButtonSubtitleSize)
emptyButtonSubtitleTransition.updateFrame(view: emptyButtonSubtitleView, frame: CGRect(origin: CGPoint(x: floor((size.width - emptyButtonSubtitleSize.width) * 0.5), y: nextY), size: emptyButtonSubtitleSize))
nextY += emptyButtonSubtitleSize.height
}
@ -5408,7 +5393,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
var emptyResultsButtonContent: EmptyResultsButton.Content?
var emptyResultsButtonSubtitleText: String?
if strongSelf.key == .globalPosts {
if strongSelf.key == .globalPosts, let globalSearchStateValue = transition.globalSearchStateValue {
if !strongSelf.isPremium {
emptyResultsButtonContent = .premiumRequired
emptyResultsTitle = "Global Search"
@ -5420,13 +5405,13 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_Search_NoResults
emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(query).string
} else {
if transition.remainingGlobalSearches != 0 {
if globalSearchStateValue.remainingFreeSearches != 0 {
emptyResultsTitle = "Global Search"
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
if transition.remainingGlobalSearches == 1 {
if globalSearchStateValue.remainingFreeSearches == 1 {
emptyResultsButtonSubtitleText = "1 free search remaining today."
} else {
emptyResultsButtonSubtitleText = "\(transition.remainingGlobalSearches) free searches remaining today."
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
}
emptyResultsButtonContent = .searchQuery(query)
@ -5435,29 +5420,29 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
emptyResultsText = "You can make up to\n10 search queries per day."
emptyResultsButtonContent = .paidSearch(
price: 10,
timestamp: transition.globalSearchUnlockTimestamp
price: Int(globalSearchStateValue.price.value),
timestamp: globalSearchStateValue.unlockTimestamp
)
}
}
} else {
if transition.remainingGlobalSearches != 0 {
if globalSearchStateValue.remainingFreeSearches != 0 {
emptyResultsButtonContent = .searchEmpty
emptyResultsTitle = "Global Search"
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
if transition.remainingGlobalSearches == 1 {
if globalSearchStateValue.remainingFreeSearches == 1 {
emptyResultsButtonSubtitleText = "1 free search remaining today."
} else {
emptyResultsButtonSubtitleText = "\(transition.remainingGlobalSearches) free searches remaining today."
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
}
} else {
emptyResultsTitle = "Limit Reached"
emptyResultsText = "You can make up to\n10 search queries per day."
emptyResultsButtonContent = .paidSearch(
price: 10,
timestamp: transition.globalSearchUnlockTimestamp
price: Int(globalSearchStateValue.price.value),
timestamp: globalSearchStateValue.unlockTimestamp
)
}
}

View File

@ -881,6 +881,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1115174036] = { return Api.SavedDialog.parse_savedDialog($0) }
dict[-881854424] = { return Api.SavedReactionTag.parse_savedReactionTag($0) }
dict[514213599] = { return Api.SavedStarGift.parse_savedStarGift($0) }
dict[-1810993028] = { return Api.SearchPostsFlood.parse_searchPostsFlood($0) }
dict[-911191137] = { return Api.SearchResultsCalendarPeriod.parse_searchResultsCalendarPeriod($0) }
dict[2137295719] = { return Api.SearchResultsPosition.parse_searchResultPosition($0) }
dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) }
@ -1381,7 +1382,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-948520370] = { return Api.messages.Messages.parse_channelMessages($0) }
dict[-1938715001] = { return Api.messages.Messages.parse_messages($0) }
dict[1951620897] = { return Api.messages.Messages.parse_messagesNotModified($0) }
dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) }
dict[1982539325] = { return Api.messages.Messages.parse_messagesSlice($0) }
dict[-83926371] = { return Api.messages.MyStickers.parse_myStickers($0) }
dict[863093588] = { return Api.messages.PeerDialogs.parse_peerDialogs($0) }
dict[1753266509] = { return Api.messages.PeerSettings.parse_peerSettings($0) }
@ -2099,6 +2100,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.SavedStarGift:
_1.serialize(buffer, boxed)
case let _1 as Api.SearchPostsFlood:
_1.serialize(buffer, boxed)
case let _1 as Api.SearchResultsCalendarPeriod:
_1.serialize(buffer, boxed)
case let _1 as Api.SearchResultsPosition:

View File

@ -294,6 +294,54 @@ public extension Api {
}
}
public extension Api {
enum SearchPostsFlood: TypeConstructorDescription {
case searchPostsFlood(flags: Int32, remains: Int32, waitTill: Int32?, starsAmount: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchPostsFlood(let flags, let remains, let waitTill, let starsAmount):
if boxed {
buffer.appendInt32(-1810993028)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(remains, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(waitTill!, buffer: buffer, boxed: false)}
serializeInt64(starsAmount, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchPostsFlood(let flags, let remains, let waitTill, let starsAmount):
return ("searchPostsFlood", [("flags", flags as Any), ("remains", remains as Any), ("waitTill", waitTill as Any), ("starsAmount", starsAmount as Any)])
}
}
public static func parse_searchPostsFlood(_ reader: BufferReader) -> SearchPostsFlood? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Int64?
_4 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.SearchPostsFlood.searchPostsFlood(flags: _1!, remains: _2!, waitTill: _3, starsAmount: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsCalendarPeriod: TypeConstructorDescription {
case searchResultsCalendarPeriod(date: Int32, minMsgId: Int32, maxMsgId: Int32, count: Int32)

View File

@ -633,7 +633,7 @@ public extension Api.messages {
case channelMessages(flags: Int32, pts: Int32, count: Int32, offsetIdOffset: Int32?, messages: [Api.Message], topics: [Api.ForumTopic], chats: [Api.Chat], users: [Api.User])
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case messagesNotModified(count: Int32)
case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, offsetIdOffset: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, offsetIdOffset: Int32?, searchFlood: Api.SearchPostsFlood?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -692,14 +692,15 @@ public extension Api.messages {
}
serializeInt32(count, buffer: buffer, boxed: false)
break
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let searchFlood, let messages, let chats, let users):
if boxed {
buffer.appendInt32(978610270)
buffer.appendInt32(1982539325)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextRate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {searchFlood!.serialize(buffer, true)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
@ -727,8 +728,8 @@ public extension Api.messages {
return ("messages", [("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
case .messagesNotModified(let count):
return ("messagesNotModified", [("count", count as Any)])
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
return ("messagesSlice", [("flags", flags as Any), ("count", count as Any), ("nextRate", nextRate as Any), ("offsetIdOffset", offsetIdOffset as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let searchFlood, let messages, let chats, let users):
return ("messagesSlice", [("flags", flags as Any), ("count", count as Any), ("nextRate", nextRate as Any), ("offsetIdOffset", offsetIdOffset as Any), ("searchFlood", searchFlood as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
@ -815,27 +816,32 @@ public extension Api.messages {
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: [Api.Message]?
var _5: Api.SearchPostsFlood?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.SearchPostsFlood
} }
var _6: [Api.Message]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.Chat]?
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _7: [Api.User]?
var _8: [Api.User]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.messages.Messages.messagesSlice(flags: _1!, count: _2!, nextRate: _3, offsetIdOffset: _4, messages: _5!, chats: _6!, users: _7!)
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.messages.Messages.messagesSlice(flags: _1!, count: _2!, nextRate: _3, offsetIdOffset: _4, searchFlood: _5, messages: _6!, chats: _7!, users: _8!)
}
else {
return nil

View File

@ -2756,6 +2756,21 @@ public extension Api.functions.bots {
})
}
}
public extension Api.functions.channels {
static func checkSearchPostsFlood() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.SearchPostsFlood>) {
let buffer = Buffer()
buffer.appendInt32(-1146490591)
return (FunctionDescription(name: "channels.checkSearchPostsFlood", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.SearchPostsFlood? in
let reader = BufferReader(buffer)
var result: Api.SearchPostsFlood?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.SearchPostsFlood
}
return result
})
}
}
public extension Api.functions.channels {
static func checkUsername(channel: Api.InputChannel, username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View File

@ -37,7 +37,7 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M
switch result {
case let .messages(_, _, users):
apiUsers = users
case let .messagesSlice(_, _, _, _, _, _, users):
case let .messagesSlice(_, _, _, _, _, _, _, users):
apiUsers = users
case let .channelMessages(_, _, _, _, _, _, _, users):
apiUsers = users

View File

@ -2683,7 +2683,7 @@ private func resolveAssociatedMessages(accountPeerId: PeerId, postbox: Postbox,
switch result {
case let .messages(messages, chats, users):
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
@ -2714,7 +2714,7 @@ private func resolveAssociatedMessages(accountPeerId: PeerId, postbox: Postbox,
switch result {
case let .messages(messages, chats, users):
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics

View File

@ -104,7 +104,7 @@ private func fetchWebpage(account: Account, messageId: MessageId, threadId: Int6
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -1087,7 +1087,7 @@ public final class AccountViewTracker {
switch result {
case let .messages(messages, chats, users):
return (peer, messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (peer, messages, chats, users)
case let .channelMessages(_, _, _, _, messages, _, chats, users):
return (peer, messages, chats, users)

View File

@ -562,7 +562,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -631,7 +631,7 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -673,7 +673,7 @@ private func validateScheduledMessagesBatch(postbox: Postbox, network: Network,
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -719,7 +719,7 @@ private func validateQuickReplyMessagesBatch(postbox: Postbox, network: Network,
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -803,7 +803,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
let _ = apiTopics
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, _, _, messages, _, _):
case let .messagesSlice(_, _, _, _, _, messages, _, _):
apiMessages = messages
case .messagesNotModified:
return Set()
@ -1052,7 +1052,7 @@ private func validateReplyThreadBatch(postbox: Postbox, network: Network, transa
let _ = apiTopics
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, _, _, messages, _, _):
case let .messagesSlice(_, _, _, _, _, messages, _, _):
apiMessages = messages
case .messagesNotModified:
return Set()

View File

@ -256,7 +256,7 @@ func withResolvedAssociatedMessages<T>(postbox: Postbox, source: FetchMessageHis
switch result {
case let .messages(messages, chats, users):
return (peer, messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (peer, messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
@ -287,7 +287,7 @@ func withResolvedAssociatedMessages<T>(postbox: Postbox, source: FetchMessageHis
switch result {
case let .messages(messages, chats, users):
return (peer, messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (peer, messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
@ -923,7 +923,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -1221,7 +1221,7 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
case let .messagesSlice(_, _, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers

View File

@ -583,7 +583,7 @@ private func synchronizeMessageHistoryTagSummary(accountPeerId: PeerId, postbox:
case let .messagesNotModified(count):
apiMessages = []
apiCount = count
case let .messagesSlice(_, count, _, _, messages, _, _):
case let .messagesSlice(_, count, _, _, _, messages, _, _):
apiMessages = messages
apiCount = count
}

View File

@ -132,7 +132,7 @@ private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox
return .single(messages.compactMap({ $0.id() }))
case .messagesNotModified:
return .single([])
case let .messagesSlice(_, _, _, _, messages, _, _):
case let .messagesSlice(_, _, _, _, _, messages, _, _):
return .single(messages.compactMap({ $0.id() }))
}
}

View File

@ -51,7 +51,7 @@ private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId
apiMessages = messages
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, _, _, messages, _, _):
case let .messagesSlice(_, _, _, _, _, messages, _, _):
apiMessages = messages
case .messagesNotModified:
apiMessages = []

View File

@ -317,6 +317,7 @@ private enum PreferencesKeyValues: Int32 {
case secureBotStorageState = 43
case serverSuggestionInfo = 44
case persistentChatInterfaceData = 45
case globalPostSearchState = 46
}
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
@ -573,6 +574,12 @@ public struct PreferencesKeys {
key.setInt64(4, value: peerId.toInt64())
return key
}
public static func globalPostSearchState() -> ValueBoxKey {
let key = ValueBoxKey(length: 4 + 8)
key.setInt32(0, value: PreferencesKeyValues.globalPostSearchState.rawValue)
return key
}
}
private enum SharedDataKeyValues: Int32 {

View File

@ -478,5 +478,23 @@ public extension TelegramEngine.EngineData.Item {
return view.info?.data.get(MessageHistoryThreadData.self)
}
}
public struct GlobalPostSearchState: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = TelegramGlobalPostSearchState?
public init() {
}
var key: PostboxViewKey {
return .preferences(keys: Set([PreferencesKeys.globalPostSearchState()]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
return view.values[PreferencesKeys.globalPostSearchState()]?.get(TelegramGlobalPostSearchState.self)
}
}
}
}

View File

@ -72,7 +72,7 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po
switch result {
case let .messages(messages, chats, users):
return (peer, messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
case let .messagesSlice(_, _, _, _, _, messages, chats, users):
return (peer, messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics

View File

@ -101,7 +101,7 @@ private func mergedState(transaction: Transaction, seedConfiguration: SeedConfig
users = apiUsers
totalCount = Int32(messages.count)
nextRate = nil
case let .messagesSlice(_, count, apiNextRate, _, apiMessages, apiChats, apiUsers):
case let .messagesSlice(_, count, apiNextRate, _, _, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -288,7 +288,7 @@ func _internal_getSearchMessageCount(account: Account, location: SearchMessagesL
return messages.count
case let .messagesNotModified(count):
return Int(count)
case let .messagesSlice(_, count, _, _, _, _, _):
case let .messagesSlice(_, count, _, _, _, _, _, _):
return Int(count)
}
}
@ -602,6 +602,26 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
}
}
if let result {
switch result {
case let .messagesSlice(_, _, _, _, searchFlood, _, _, _):
if let searchFlood {
transaction.updatePreferencesEntry(key: PreferencesKeys.globalPostSearchState(), { _ in
switch searchFlood {
case let .searchPostsFlood(_, remains, waitTill, starsAmount):
return PreferencesEntry(TelegramGlobalPostSearchState(
remainingFreeSearches: remains,
price: StarsAmount(value: starsAmount, nanos: 0),
unlockTimestamp: waitTill
))
}
})
}
default:
break
}
}
let updatedState = SearchMessagesState(main: mergedState(transaction: transaction, seedConfiguration: account.postbox.seedConfiguration, accountPeerId: account.peerId, state: state?.main, result: result) ?? SearchMessagesPeerState(messages: [], readStates: [:], threadInfo: [:], totalCount: 0, completed: true, nextRate: nil), additional: additional)
return (mergedResult(updatedState), updatedState)
}
@ -682,7 +702,7 @@ func _internal_downloadMessage(accountPeerId: PeerId, postbox: Postbox, network:
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .messagesSlice(_, _, _, _, _, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -773,7 +793,7 @@ func fetchRemoteMessage(accountPeerId: PeerId, postbox: Postbox, source: FetchMe
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .messagesSlice(_, _, _, _, _, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
@ -839,7 +859,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _):
messages = apiMessages
case .messagesNotModified:
messages = []
@ -876,7 +896,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _):
messages = apiMessages
case .messagesNotModified:
messages = []
@ -909,7 +929,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _):
messages = apiMessages
case .messagesNotModified:
messages = []
@ -933,7 +953,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _):
messages = apiMessages
case .messagesNotModified:
messages = []
@ -1067,3 +1087,29 @@ func _internal_updatedRemotePeer(accountPeerId: PeerId, postbox: Postbox, networ
return .fail(.generic)
}
}
func _internal_refreshGlobalPostSearchState(account: Account) -> Signal<Never, NoError> {
return account.network.request(Api.functions.channels.checkSearchPostsFlood())
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.SearchPostsFlood?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<Never, NoError> in
return account.postbox.transaction { transaction -> Void in
guard let result else {
return
}
transaction.updatePreferencesEntry(key: PreferencesKeys.globalPostSearchState(), { _ in
switch result {
case let .searchPostsFlood(_, remains, waitTill, starsAmount):
return PreferencesEntry(TelegramGlobalPostSearchState(
remainingFreeSearches: remains,
price: StarsAmount(value: starsAmount, nanos: 0),
unlockTimestamp: waitTill
))
}
})
}
|> ignoreValues
}
}

View File

@ -37,6 +37,31 @@ public final class StoryPreloadInfo {
}
}
public final class TelegramGlobalPostSearchState: Codable, Equatable {
public let remainingFreeSearches: Int32
public let price: StarsAmount
public let unlockTimestamp: Int32?
public init(remainingFreeSearches: Int32, price: StarsAmount, unlockTimestamp: Int32?) {
self.remainingFreeSearches = remainingFreeSearches
self.price = price
self.unlockTimestamp = unlockTimestamp
}
public static func ==(lhs: TelegramGlobalPostSearchState, rhs: TelegramGlobalPostSearchState) -> Bool {
if lhs.remainingFreeSearches != rhs.remainingFreeSearches {
return false
}
if lhs.price != rhs.price {
return false
}
if lhs.unlockTimestamp != rhs.unlockTimestamp {
return false
}
return true
}
}
public extension TelegramEngine {
final class Messages {
private let account: Account
@ -514,7 +539,7 @@ public extension TelegramEngine {
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, savedPeerId: inputSavedPeer, savedReaction: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> (count: Int32?, topId: Int32?) in
switch result {
case let .messagesSlice(_, count, _, _, messages, _, _):
case let .messagesSlice(_, count, _, _, _, messages, _, _):
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case let .channelMessages(_, _, count, _, messages, _, _, _):
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
@ -1597,6 +1622,10 @@ public extension TelegramEngine {
public func monoforumPerformSuggestedPostAction(id: EngineMessage.Id, action: MonoforumSuggestedPostAction) -> Signal<Never, NoError> {
return _internal_monoforumPerformSuggestedPostAction(account: self.account, id: id, action: action)
}
public func refreshGlobalPostSearchState() -> Signal<Never, NoError> {
return _internal_refreshGlobalPostSearchState(account: self.account)
}
}
}

View File

@ -87,7 +87,7 @@ func _internal_requestPeerPhotos(accountPeerId: PeerId, postbox: Postbox, networ
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .messagesSlice(_, _, _, _, _, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers