From 38464954b095b1bd8063234f1a0fc8437d8b79b4 Mon Sep 17 00:00:00 2001 From: isaac <> Date: Sun, 24 May 2026 00:24:21 +0400 Subject: [PATCH] Update API --- submodules/TelegramApi/Sources/Api0.swift | 1 + submodules/TelegramApi/Sources/Api19.swift | 31 +++++++++++++++++ submodules/TelegramApi/Sources/Api42.swift | 7 ++-- .../Account/AccountIntermediateState.swift | 33 ++++++++++++------- .../Sources/ApiUtils/InstantPage.swift | 2 +- .../State/AccountStateManagementUtils.swift | 24 +++++++------- .../Sources/State/ContactSyncManager.swift | 8 ++--- .../TelegramEngine/Peers/SearchPeers.swift | 2 +- .../TelegramCore/Sources/UpdatePeers.swift | 24 +++++++++++--- 9 files changed, 94 insertions(+), 38 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index a22e35e6d6..ae1b5a7e68 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -790,6 +790,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-248793375] = { return Api.PageBlock.parse_pageBlockSubheader($0) } dict[-1879401953] = { return Api.PageBlock.parse_pageBlockSubtitle($0) } dict[-1085412734] = { return Api.PageBlock.parse_pageBlockTable($0) } + dict[1009361890] = { return Api.PageBlock.parse_pageBlockThinking($0) } dict[1890305021] = { return Api.PageBlock.parse_pageBlockTitle($0) } dict[324435594] = { return Api.PageBlock.parse_pageBlockUnsupported($0) } dict[2089805750] = { return Api.PageBlock.parse_pageBlockVideo($0) } diff --git a/submodules/TelegramApi/Sources/Api19.swift b/submodules/TelegramApi/Sources/Api19.swift index 204a270064..542180c858 100644 --- a/submodules/TelegramApi/Sources/Api19.swift +++ b/submodules/TelegramApi/Sources/Api19.swift @@ -797,6 +797,15 @@ public extension Api { return ("pageBlockTable", [("flags", ConstructorParameterDescription(self.flags)), ("title", ConstructorParameterDescription(self.title)), ("rows", ConstructorParameterDescription(self.rows))]) } } + public class Cons_pageBlockThinking: TypeConstructorDescription { + public var text: Api.RichText + public init(text: Api.RichText) { + self.text = text + } + public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) { + return ("pageBlockThinking", [("text", ConstructorParameterDescription(self.text))]) + } + } public class Cons_pageBlockTitle: TypeConstructorDescription { public var text: Api.RichText public init(text: Api.RichText) { @@ -854,6 +863,7 @@ public extension Api { case pageBlockSubheader(Cons_pageBlockSubheader) case pageBlockSubtitle(Cons_pageBlockSubtitle) case pageBlockTable(Cons_pageBlockTable) + case pageBlockThinking(Cons_pageBlockThinking) case pageBlockTitle(Cons_pageBlockTitle) case pageBlockUnsupported case pageBlockVideo(Cons_pageBlockVideo) @@ -1162,6 +1172,12 @@ public extension Api { item.serialize(buffer, true) } break + case .pageBlockThinking(let _data): + if boxed { + buffer.appendInt32(1009361890) + } + _data.text.serialize(buffer, true) + break case .pageBlockTitle(let _data): if boxed { buffer.appendInt32(1890305021) @@ -1256,6 +1272,8 @@ public extension Api { return ("pageBlockSubtitle", [("text", ConstructorParameterDescription(_data.text))]) case .pageBlockTable(let _data): return ("pageBlockTable", [("flags", ConstructorParameterDescription(_data.flags)), ("title", ConstructorParameterDescription(_data.title)), ("rows", ConstructorParameterDescription(_data.rows))]) + case .pageBlockThinking(let _data): + return ("pageBlockThinking", [("text", ConstructorParameterDescription(_data.text))]) case .pageBlockTitle(let _data): return ("pageBlockTitle", [("text", ConstructorParameterDescription(_data.text))]) case .pageBlockUnsupported: @@ -1861,6 +1879,19 @@ public extension Api { return nil } } + public static func parse_pageBlockThinking(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockThinking(Cons_pageBlockThinking(text: _1!)) + } + else { + return nil + } + } public static func parse_pageBlockTitle(_ reader: BufferReader) -> PageBlock? { var _1: Api.RichText? if let signature = reader.readInt32() { diff --git a/submodules/TelegramApi/Sources/Api42.swift b/submodules/TelegramApi/Sources/Api42.swift index 1f1ca0591a..3879eaff5a 100644 --- a/submodules/TelegramApi/Sources/Api42.swift +++ b/submodules/TelegramApi/Sources/Api42.swift @@ -4922,12 +4922,13 @@ public extension Api.functions.contacts { } } public extension Api.functions.contacts { - static func search(q: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func search(flags: Int32, q: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(301470424) + buffer.appendInt32(99978511) + serializeInt32(flags, buffer: buffer, boxed: false) serializeString(q, buffer: buffer, boxed: false) serializeInt32(limit, buffer: buffer, boxed: false) - return (FunctionDescription(name: "contacts.search", parameters: [("q", ConstructorParameterDescription(q)), ("limit", ConstructorParameterDescription(limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.Found? in + return (FunctionDescription(name: "contacts.search", parameters: [("flags", ConstructorParameterDescription(flags)), ("q", ConstructorParameterDescription(q)), ("limit", ConstructorParameterDescription(limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.Found? in let reader = BufferReader(buffer) var result: Api.contacts.Found? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 8d242b02dd..a697ec8ff6 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -64,6 +64,16 @@ enum AccountStateGlobalNotificationSettingsSubject { case channels } +struct UpdatedApiPresence { + var status: Api.UserStatus + var isMin: Bool + + init(status: Api.UserStatus, isMin: Bool) { + self.status = status + self.isMin = isMin + } +} + enum AccountStateMutationOperation { case AddMessages([StoreMessage], AddMessagesLocation) case AddScheduledMessages([StoreMessage]) @@ -93,7 +103,7 @@ enum AccountStateMutationOperation { case UpdateCachedPeerData(PeerId, (CachedPeerData?) -> CachedPeerData?) case UpdateMessagesPinned([MessageId], Bool) case MergeApiUsers([Api.User]) - case MergePeerPresences([PeerId: Api.UserStatus], Bool) + case MergePeerPresences([PeerId: UpdatedApiPresence], Bool) case UpdateSecretChat(chat: Api.EncryptedChat, timestamp: Int32) case AddSecretMessages([Api.EncryptedMessage]) case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32) @@ -575,17 +585,18 @@ struct AccountMutableState { mutating func mergeUsers(_ users: [Api.User]) { self.addOperation(.MergeApiUsers(users)) - var presences: [PeerId: Api.UserStatus] = [:] + var presences: [PeerId: UpdatedApiPresence] = [:] for user in users { switch user { - case let .user(userData): - let (id, status) = (userData.id, userData.status) - if let status = status { - presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))] = status - } - break - case .userEmpty: - break + case let .user(userData): + let (id, status) = (userData.id, userData.status) + let isMin = (userData.flags & (1 << 20)) != 0 + if let status = status { + presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))] = UpdatedApiPresence(status: status, isMin: isMin) + } + break + case .userEmpty: + break } } if !presences.isEmpty { @@ -594,7 +605,7 @@ struct AccountMutableState { } mutating func mergePeerPresences(_ presences: [PeerId: Api.UserStatus], explicit: Bool) { - self.addOperation(.MergePeerPresences(presences, explicit)) + self.addOperation(.MergePeerPresences(presences.mapValues({ UpdatedApiPresence(status: $0, isMin: false) }), explicit)) } mutating func updateSecretChat(chat: Api.EncryptedChat, timestamp: Int32) { diff --git a/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift b/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift index 01152ca275..0f04e22fe8 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/InstantPage.swift @@ -302,7 +302,7 @@ extension InstantPageBlock { self = .heading(text: RichText(apiText: pageBlockHeading6.text), level: 6) case let .pageBlockMath(pageBlockMath): self = .formula(latex: pageBlockMath.source) - case .inputPageBlockMap, .inputPageBlockOrderedList: + case .inputPageBlockMap, .inputPageBlockOrderedList, .pageBlockThinking: self = .unsupported } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 2c3b848488..d330ae4782 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -4923,26 +4923,24 @@ func replayFinalState( }) } case let .MergePeerPresences(statuses, explicit): - var presences: [PeerId: PeerPresence] = [:] + var presences: [PeerId: UpdatedApiPresence] = [:] for (peerId, status) in statuses { if peerId == accountPeerId { if explicit { - switch status { - case let .userStatusOnline(userStatusOnlineData): - let timestamp = userStatusOnlineData.expires - delayNotificatonsUntil = timestamp + 30 - case let .userStatusOffline(userStatusOfflineData): - let timestamp = userStatusOfflineData.wasOnline - delayNotificatonsUntil = timestamp - default: - break + switch status.status { + case let .userStatusOnline(userStatusOnlineData): + let timestamp = userStatusOnlineData.expires + delayNotificatonsUntil = timestamp + 30 + case let .userStatusOffline(userStatusOfflineData): + let timestamp = userStatusOfflineData.wasOnline + delayNotificatonsUntil = timestamp + default: + break } } } else { - let presence = TelegramUserPresence(apiStatus: status) - presences[peerId] = presence + presences[peerId] = status } - } updatePeerPresencesClean(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences) case let .UpdateSecretChat(chat, _): diff --git a/submodules/TelegramCore/Sources/State/ContactSyncManager.swift b/submodules/TelegramCore/Sources/State/ContactSyncManager.swift index 76c2660344..7c6cfff113 100644 --- a/submodules/TelegramCore/Sources/State/ContactSyncManager.swift +++ b/submodules/TelegramCore/Sources/State/ContactSyncManager.swift @@ -405,12 +405,12 @@ private func updateContactPresences(postbox: Postbox, network: Network, accountP } |> mapToSignal { statuses -> Signal in return postbox.transaction { transaction -> Void in - var peerPresences: [PeerId: PeerPresence] = [:] + var peerPresences: [PeerId: UpdatedApiPresence] = [:] for status in statuses { switch status { - case let .contactStatus(contactStatusData): - let (userId, status) = (contactStatusData.userId, contactStatusData.status) - peerPresences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))] = TelegramUserPresence(apiStatus: status) + case let .contactStatus(contactStatusData): + let (userId, status) = (contactStatusData.userId, contactStatusData.status) + peerPresences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))] = UpdatedApiPresence(status: status, isMin: false) } } updatePeerPresencesClean(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift index e82a0a009c..30e8a3c0e4 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift @@ -27,7 +27,7 @@ public enum TelegramSearchPeersScope: Equatable { } public func _internal_searchPeers(accountPeerId: PeerId, postbox: Postbox, network: Network, query: String, scope: TelegramSearchPeersScope) -> Signal<([FoundPeer], [FoundPeer]), NoError> { - let searchResult = network.request(Api.functions.contacts.search(q: query, limit: 20), automaticFloodWait: false) + let searchResult = network.request(Api.functions.contacts.search(flags: 0, q: query, limit: 20), automaticFloodWait: false) |> map(Optional.init) |> `catch` { _ in return Signal.single(nil) diff --git a/submodules/TelegramCore/Sources/UpdatePeers.swift b/submodules/TelegramCore/Sources/UpdatePeers.swift index 53db73d1ad..b7aaa24f26 100644 --- a/submodules/TelegramCore/Sources/UpdatePeers.swift +++ b/submodules/TelegramCore/Sources/UpdatePeers.swift @@ -360,12 +360,26 @@ func updatePeerPresences(transaction: Transaction, accountPeerId: PeerId, peerPr }) } -func updatePeerPresencesClean(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: PeerPresence]) { - var peerPresences = peerPresences - if peerPresences[accountPeerId] != nil { - peerPresences.removeValue(forKey: accountPeerId) +func updatePeerPresencesClean(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: UpdatedApiPresence]) { + var parsedPresences: [PeerId: PeerPresence] = [:] + for (peerId, status) in peerPresences { + let presence = TelegramUserPresence(apiStatus: status.status) + switch presence.status { + case .present: + parsedPresences[peerId] = presence + default: + if status.isMin, let _ = transaction.getPeerPresence(peerId: peerId) { + } else { + parsedPresences[peerId] = presence + } + } } - transaction.updatePeerPresencesInternal(presences: peerPresences, merge: { previous, updated in + + if parsedPresences[accountPeerId] != nil { + parsedPresences.removeValue(forKey: accountPeerId) + } + + transaction.updatePeerPresencesInternal(presences: parsedPresences, merge: { previous, updated in if let previous = previous as? TelegramUserPresence, let updated = updated as? TelegramUserPresence, previous.lastActivity != updated.lastActivity { return TelegramUserPresence(status: updated.status, lastActivity: max(previous.lastActivity, updated.lastActivity)) }