[WIP] Saved messages

This commit is contained in:
Isaac 2023-12-23 00:47:22 +04:00
parent 624155ae99
commit 0ad61d8d63
71 changed files with 2079 additions and 1024 deletions

View file

@ -423,7 +423,7 @@ public final class NavigateToChatControllerParams {
case let .peer(peer):
return peer.id
case let .replyThread(message):
return message.messageId.peerId
return message.peerId
}
}
@ -432,7 +432,7 @@ public final class NavigateToChatControllerParams {
case .peer:
return nil
case let .replyThread(message):
return Int64(message.messageId.id)
return message.threadId
}
}

View file

@ -35,7 +35,7 @@ public enum PeerMessagesPlaylistLocation: Equatable, SharedMediaPlaylistLocation
case let .peer(peerId):
return .peer(peerId)
case let .replyThread(replyThreaMessage):
return .peer(replyThreaMessage.messageId.peerId)
return .peer(replyThreaMessage.peerId)
case let .feed(id):
return .feed(id)
}

View file

@ -1345,7 +1345,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if let threadId = threadId {
let source: ContextContentSource
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
messageId: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
peerId: peer.peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
@ -1381,7 +1381,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
let source: ContextContentSource
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
messageId: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
peerId: peer.peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))

View file

@ -1539,9 +1539,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
let searchLocations: [SearchMessagesLocation]
if let options = options {
if case let .forum(peerId) = location {
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
} else if let (peerId, _, _) = options.peer {
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: options.date?.0, maxDate: options.date?.1)]
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1)]
} else {
if case let .chatList(groupId) = location, case .archive = groupId {
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
@ -1551,7 +1551,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
}
} else {
if case let .forum(peerId) = location {
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: nil, maxDate: nil), .general(tags: tagMask, minDate: nil, maxDate: nil)]
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, threadId: nil, minDate: nil, maxDate: nil), .general(tags: tagMask, minDate: nil, maxDate: nil)]
} else if case let .chatList(groupId) = location, case .archive = groupId {
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: nil, maxDate: nil)]
} else {

View file

@ -124,13 +124,13 @@ final class ShimmerEffectNode: ASDisplayNode {
}
}
final class ChatListShimmerNode: ASDisplayNode {
public final class ChatListShimmerNode: ASDisplayNode {
private let backgroundColorNode: ASDisplayNode
private let effectNode: ShimmerEffectNode
private let maskNode: ASImageNode
private var currentParams: (size: CGSize, presentationData: PresentationData)?
override init() {
override public init() {
self.backgroundColorNode = ASDisplayNode()
self.effectNode = ShimmerEffectNode()
self.maskNode = ASImageNode()
@ -144,7 +144,7 @@ final class ChatListShimmerNode: ASDisplayNode {
self.addSubnode(self.maskNode)
}
func update(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, size: CGSize, isInlineMode: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
public func update(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, size: CGSize, isInlineMode: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
if self.currentParams?.size != size || self.currentParams?.presentationData !== presentationData {
self.currentParams = (size, presentationData)

View file

@ -312,65 +312,35 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
return ChatListNodeViewUpdate(list: list, type: type, scrollPosition: nil)
}
case .savedMessagesChats:
var isFirst = true
return account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 1000, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal])), orderStatistics: [])
|> map { view, _, _ -> ChatListNodeViewUpdate in
let isLoading = view.isLoading
if "".isEmpty {
let viewKey: PostboxViewKey = .savedMessagesIndex(peerId: account.peerId)
var items: [EngineChatList.Item] = []
var topMessageByPeerId: [EnginePeer.Id: Message] = [:]
if !isLoading {
for entry in view.entries {
guard let threadId = entry.message.threadId else {
continue
}
let sourcePeerId = PeerId(threadId)
if let currentTopMessage = topMessageByPeerId[sourcePeerId] {
if currentTopMessage.index < entry.index {
topMessageByPeerId[sourcePeerId] = entry.message
}
} else {
topMessageByPeerId[sourcePeerId] = entry.message
}
var isFirst = true
return account.postbox.combinedView(keys: [viewKey])
|> map { views -> ChatListNodeViewUpdate in
guard let view = views.views[viewKey] as? MessageHistorySavedMessagesIndexView else {
preconditionFailure()
}
for (_, message) in topMessageByPeerId.sorted(by: { $0.value.index > $1.value.index }) {
guard let threadId = message.threadId else {
var items: [EngineChatList.Item] = []
for item in view.items {
guard let sourcePeer = item.peer else {
continue
}
let sourceId = PeerId(threadId)
var sourcePeer = message.peers[sourceId]
if sourcePeer == nil, let forwardInfo = message.forwardInfo, let authorSignature = forwardInfo.authorSignature {
sourcePeer = TelegramUser(
id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(1)),
accessHash: nil,
firstName: authorSignature,
lastName: nil,
username: nil,
phone: nil,
photo: [],
botInfo: nil,
restrictionInfo: nil,
flags: [],
emojiStatus: nil,
usernames: [],
storiesHidden: nil,
nameColor: nil,
backgroundEmojiId: nil,
profileColor: nil,
profileBackgroundEmojiId: nil
)
let sourceId = PeerId(item.id)
var messages: [EngineMessage] = []
if let topMessage = item.topMessage {
messages.append(EngineMessage(topMessage))
}
guard let sourcePeer else {
continue
}
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: message.index.id.namespace, id: message.index.id.id), timestamp: message.index.timestamp)
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: item.index.id.namespace, id: item.index.id.id), timestamp: item.index.timestamp)
items.append(EngineChatList.Item(
id: .chatList(sourceId),
index: .chatList(ChatListIndex(pinningIndex: nil, messageIndex: mappedMessageIndex)),
messages: [EngineMessage(message)],
index: .chatList(ChatListIndex(pinningIndex: item.pinnedIndex.flatMap(UInt16.init), messageIndex: mappedMessageIndex)),
messages: messages,
readCounters: nil,
isMuted: false,
draft: nil,
@ -387,25 +357,121 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
storyStats: nil
))
}
let list = EngineChatList(
items: items.reversed(),
groupItems: [],
additionalItems: [],
hasEarlier: false,
hasLater: false,
isLoading: view.isLoading
)
let type: ViewUpdateType
if isFirst {
type = .Initial
} else {
type = .Generic
}
isFirst = false
return ChatListNodeViewUpdate(list: list, type: type, scrollPosition: nil)
}
} else {
var isFirst = true
let list = EngineChatList(
items: items.reversed(),
groupItems: [],
additionalItems: [],
hasEarlier: false,
hasLater: false,
isLoading: isLoading
)
let type: ViewUpdateType
if isFirst {
type = .Initial
} else {
type = .Generic
return account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 1000, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal])), orderStatistics: [])
|> map { view, _, _ -> ChatListNodeViewUpdate in
let isLoading = view.isLoading
var items: [EngineChatList.Item] = []
var topMessageByPeerId: [EnginePeer.Id: Message] = [:]
if !isLoading {
for entry in view.entries {
guard let threadId = entry.message.threadId else {
continue
}
let sourcePeerId = PeerId(threadId)
if let currentTopMessage = topMessageByPeerId[sourcePeerId] {
if currentTopMessage.index < entry.index {
topMessageByPeerId[sourcePeerId] = entry.message
}
} else {
topMessageByPeerId[sourcePeerId] = entry.message
}
}
for (_, message) in topMessageByPeerId.sorted(by: { $0.value.index > $1.value.index }) {
guard let threadId = message.threadId else {
continue
}
let sourceId = PeerId(threadId)
var sourcePeer = message.peers[sourceId]
if sourcePeer == nil, let forwardInfo = message.forwardInfo, let authorSignature = forwardInfo.authorSignature {
sourcePeer = TelegramUser(
id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(1)),
accessHash: nil,
firstName: authorSignature,
lastName: nil,
username: nil,
phone: nil,
photo: [],
botInfo: nil,
restrictionInfo: nil,
flags: [],
emojiStatus: nil,
usernames: [],
storiesHidden: nil,
nameColor: nil,
backgroundEmojiId: nil,
profileColor: nil,
profileBackgroundEmojiId: nil
)
}
guard let sourcePeer else {
continue
}
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: message.index.id.namespace, id: message.index.id.id), timestamp: message.index.timestamp)
items.append(EngineChatList.Item(
id: .chatList(sourceId),
index: .chatList(ChatListIndex(pinningIndex: nil, messageIndex: mappedMessageIndex)),
messages: [EngineMessage(message)],
readCounters: nil,
isMuted: false,
draft: nil,
threadData: nil,
renderedPeer: EngineRenderedPeer(peer: EnginePeer(sourcePeer)),
presence: nil,
hasUnseenMentions: false,
hasUnseenReactions: false,
forumTopicData: nil,
topForumTopicItems: [],
hasFailed: false,
isContact: false,
autoremoveTimeout: nil,
storyStats: nil
))
}
}
let list = EngineChatList(
items: items.reversed(),
groupItems: [],
additionalItems: [],
hasEarlier: false,
hasLater: false,
isLoading: isLoading
)
let type: ViewUpdateType
if isFirst {
type = .Initial
} else {
type = .Generic
}
isFirst = false
return ChatListNodeViewUpdate(list: list, type: type, scrollPosition: nil)
}
isFirst = false
return ChatListNodeViewUpdate(list: list, type: type, scrollPosition: nil)
}
}
}

View file

@ -14,7 +14,7 @@ public extension ChatLocation {
case let .peer(peerId):
return peerId
case let .replyThread(replyThreadMessage):
return replyThreadMessage.messageId.peerId
return replyThreadMessage.peerId
case .feed:
return nil
}
@ -25,7 +25,7 @@ public extension ChatLocation {
case .peer:
return nil
case let .replyThread(replyThreadMessage):
return Int64(replyThreadMessage.messageId.id)
return replyThreadMessage.threadId
case .feed:
return nil
}

View file

@ -869,14 +869,14 @@ public enum StoreMessageId {
}
}
public func makeMessageThreadId(_ messageId: MessageId) -> Int64 {
return (Int64(messageId.namespace) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: messageId.id)))
}
public func makeThreadIdMessageId(peerId: PeerId, threadId: Int64) -> MessageId {
let namespace = Int32((threadId >> 32) & 0x7fffffff)
let id = Int32(bitPattern: UInt32(threadId & 0xffffffff))
return MessageId(peerId: peerId, namespace: namespace, id: id)
public struct MessageThreadKey: Hashable {
public var peerId: PeerId
public var threadId: Int64
public init(peerId: PeerId, threadId: Int64) {
self.peerId = peerId
self.threadId = threadId
}
}
public final class StoreMessage {

View file

@ -0,0 +1,189 @@
import Foundation
final class MutableMessageHistorySavedMessagesIndexView: MutablePostboxView {
final class Item {
let id: Int64
let peer: Peer?
let pinnedIndex: Int?
let index: MessageIndex
let topMessage: Message?
init(
id: Int64,
peer: Peer?,
pinnedIndex: Int?,
index: MessageIndex,
topMessage: Message?
) {
self.id = id
self.peer = peer
self.pinnedIndex = pinnedIndex
self.index = index
self.topMessage = topMessage
}
}
fileprivate let peerId: PeerId
fileprivate var peer: Peer?
fileprivate var items: [Item] = []
private var hole: ForumTopicListHolesEntry?
fileprivate var isLoading: Bool = false
init(postbox: PostboxImpl, peerId: PeerId) {
self.peerId = peerId
self.reload(postbox: postbox)
}
private func reload(postbox: PostboxImpl) {
self.items.removeAll()
self.peer = postbox.peerTable.get(self.peerId)
let validIndexBoundary = postbox.peerThreadCombinedStateTable.get(peerId: peerId)?.validIndexBoundary
self.isLoading = validIndexBoundary == nil
if let validIndexBoundary = validIndexBoundary {
if validIndexBoundary.messageId != 1 {
self.hole = ForumTopicListHolesEntry(peerId: self.peerId, index: validIndexBoundary)
} else {
self.hole = nil
}
} else {
self.hole = ForumTopicListHolesEntry(peerId: self.peerId, index: nil)
}
if !self.isLoading {
let pinnedThreadIds = postbox.messageHistoryThreadPinnedTable.get(peerId: self.peerId)
for item in postbox.messageHistoryThreadIndexTable.getAll(peerId: self.peerId) {
var pinnedIndex: Int?
if let index = pinnedThreadIds.firstIndex(of: item.threadId) {
pinnedIndex = index
}
self.items.append(Item(
id: item.threadId,
peer: postbox.peerTable.get(PeerId(item.threadId)),
pinnedIndex: pinnedIndex,
index: item.index,
topMessage: postbox.getMessage(item.index.id)
))
}
self.items.sort(by: { lhs, rhs in
if let lhsPinnedIndex = lhs.pinnedIndex, let rhsPinnedIndex = rhs.pinnedIndex {
return lhsPinnedIndex < rhsPinnedIndex
} else if (lhs.pinnedIndex == nil) != (rhs.pinnedIndex == nil) {
if lhs.pinnedIndex != nil {
return true
} else {
return false
}
}
return lhs.index > rhs.index
})
}
}
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
var updated = false
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) || transaction.updatedPinnedThreads.contains(self.peerId) || transaction.updatedPeerThreadCombinedStates.contains(self.peerId) || transaction.currentUpdatedMessageTagSummaries.contains(where: { $0.key.peerId == self.peerId }) || transaction.currentUpdatedMessageActionsSummaries.contains(where: { $0.key.peerId == self.peerId }) || transaction.currentUpdatedPeerChatListEmbeddedStates.contains(self.peerId) || transaction.currentUpdatedPeerNotificationSettings[self.peerId] != nil || transaction.updatedPinnedThreads.contains(self.peerId) {
self.reload(postbox: postbox)
updated = true
}
return updated
}
func topHole() -> ForumTopicListHolesEntry? {
return self.hole
}
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
self.reload(postbox: postbox)
return true
}
func immutableView() -> PostboxView {
return MessageHistorySavedMessagesIndexView(self)
}
}
public final class EngineMessageHistorySavedMessagesThread {
public final class Item: Equatable {
public let id: Int64
public let peer: Peer?
public let pinnedIndex: Int?
public let index: MessageIndex
public let topMessage: Message?
public init(
id: Int64,
peer: Peer?,
pinnedIndex: Int?,
index: MessageIndex,
topMessage: Message?
) {
self.id = id
self.peer = peer
self.pinnedIndex = pinnedIndex
self.index = index
self.topMessage = topMessage
}
public static func ==(lhs: Item, rhs: Item) -> Bool {
if lhs.id != rhs.id {
return false
}
if !arePeersEqual(lhs.peer, rhs.peer) {
return false
}
if lhs.pinnedIndex != rhs.pinnedIndex {
return false
}
if lhs.index != rhs.index {
return false
}
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
if lhsMessage.index != rhsMessage.index {
return false
}
if lhsMessage.stableVersion != rhsMessage.stableVersion {
return false
}
} else if (lhs.topMessage == nil) != (rhs.topMessage == nil) {
return false
}
return true
}
}
}
public final class MessageHistorySavedMessagesIndexView: PostboxView {
public let peer: Peer?
public let items: [EngineMessageHistorySavedMessagesThread.Item]
public let isLoading: Bool
init(_ view: MutableMessageHistorySavedMessagesIndexView) {
self.peer = view.peer
var items: [EngineMessageHistorySavedMessagesThread.Item] = []
for item in view.items {
items.append(EngineMessageHistorySavedMessagesThread.Item(
id: item.id,
peer: item.peer,
pinnedIndex: item.pinnedIndex,
index: item.index,
topMessage: item.topMessage
))
}
self.items = items
self.isLoading = view.isLoading
}
}

View file

@ -119,13 +119,15 @@ class MessageHistoryThreadIndexTable: Table {
}
private let reverseIndexTable: MessageHistoryThreadReverseIndexTable
private let seedConfiguration: SeedConfiguration
private let sharedKey = ValueBoxKey(length: 8 + 4 + 8 + 4 + 4)
private var updatedInfoItems: [MessageHistoryThreadsTable.ItemId: UpdatedEntry] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, reverseIndexTable: MessageHistoryThreadReverseIndexTable, useCaches: Bool) {
init(valueBox: ValueBox, table: ValueBoxTable, reverseIndexTable: MessageHistoryThreadReverseIndexTable, seedConfiguration: SeedConfiguration, useCaches: Bool) {
self.reverseIndexTable = reverseIndexTable
self.seedConfiguration = seedConfiguration
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
@ -219,6 +221,13 @@ class MessageHistoryThreadIndexTable: Table {
info = nil
}
}
if info == nil {
if let value = self.seedConfiguration.automaticThreadIndexInfo(itemId.peerId, itemId.threadId) {
let encoder = PostboxEncoder()
value.encode(encoder)
info = encoder.makeReadBufferAndReset()
}
}
if let topIndex = topIndex, let info = info {
if let previousIndex = previousIndex {

View file

@ -1746,7 +1746,7 @@ final class PostboxImpl {
self.messageHistoryThreadTagsTable = MessageHistoryThreadTagsTable(valueBox: self.valueBox, table: MessageHistoryThreadTagsTable.tableSpec(71), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.messageHistoryThreadReverseIndexTable = MessageHistoryThreadReverseIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadReverseIndexTable.tableSpec(72), useCaches: useCaches)
self.messageHistoryThreadIndexTable = MessageHistoryThreadIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadIndexTable.tableSpec(73), reverseIndexTable: self.messageHistoryThreadReverseIndexTable, useCaches: useCaches)
self.messageHistoryThreadIndexTable = MessageHistoryThreadIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadIndexTable.tableSpec(73), reverseIndexTable: self.messageHistoryThreadReverseIndexTable, seedConfiguration: seedConfiguration, useCaches: useCaches)
self.messageHistoryThreadPinnedTable = MessageHistoryThreadPinnedTable(valueBox: self.valueBox, table: MessageHistoryThreadPinnedTable.tableSpec(76), useCaches: useCaches)
self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39), useCaches: useCaches)
self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52), useCaches: useCaches)

View file

@ -78,6 +78,7 @@ public final class SeedConfiguration {
public let decodeAutoremoveTimeout: (CachedPeerData) -> Int32?
public let decodeDisplayPeerAsRegularChat: (CachedPeerData) -> Bool
public let isPeerUpgradeMessage: (Message) -> Bool
public let automaticThreadIndexInfo: (PeerId, Int64) -> StoredMessageHistoryThreadInfo?
public init(
globalMessageIdsPeerIdNamespaces: Set<GlobalMessageIdsNamespace>,
@ -105,7 +106,8 @@ public final class SeedConfiguration {
decodeMessageThreadInfo: @escaping (CodableEntry) -> Message.AssociatedThreadInfo?,
decodeAutoremoveTimeout: @escaping (CachedPeerData) -> Int32?,
decodeDisplayPeerAsRegularChat: @escaping (CachedPeerData) -> Bool,
isPeerUpgradeMessage: @escaping (Message) -> Bool
isPeerUpgradeMessage: @escaping (Message) -> Bool,
automaticThreadIndexInfo: @escaping (PeerId, Int64) -> StoredMessageHistoryThreadInfo?
) {
self.globalMessageIdsPeerIdNamespaces = globalMessageIdsPeerIdNamespaces
self.initializeChatListWithHole = initializeChatListWithHole
@ -129,5 +131,6 @@ public final class SeedConfiguration {
self.decodeAutoremoveTimeout = decodeAutoremoveTimeout
self.decodeDisplayPeerAsRegularChat = decodeDisplayPeerAsRegularChat
self.isPeerUpgradeMessage = isPeerUpgradeMessage
self.automaticThreadIndexInfo = automaticThreadIndexInfo
}
}

View file

@ -453,6 +453,10 @@ final class ViewTracker {
if let hole = view.topHole() {
firstHoles.insert(hole)
}
} else if case .savedMessagesIndex = key, let view = view as? MutableMessageHistorySavedMessagesIndexView {
if let hole = view.topHole() {
firstHoles.insert(hole)
}
}
}
}

View file

@ -46,6 +46,7 @@ public enum PostboxViewKey: Hashable {
case storyExpirationTimeItems
case peerStoryStats(peerIds: Set<PeerId>)
case story(id: StoryId)
case savedMessagesIndex(peerId: PeerId)
public func hash(into hasher: inout Hasher) {
switch self {
@ -153,6 +154,8 @@ public enum PostboxViewKey: Hashable {
hasher.combine(peerIds)
case let .story(id):
hasher.combine(id)
case let .savedMessagesIndex(peerId):
hasher.combine(peerId)
}
}
@ -428,6 +431,12 @@ public enum PostboxViewKey: Hashable {
} else {
return false
}
case let .savedMessagesIndex(peerId):
if case .savedMessagesIndex(peerId) = rhs {
return true
} else {
return false
}
}
}
}
@ -524,5 +533,7 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
return MutablePeerStoryStatsView(postbox: postbox, peerIds: peerIds)
case let .story(id):
return MutableStoryView(postbox: postbox, id: id)
case let .savedMessagesIndex(peerId):
return MutableMessageHistorySavedMessagesIndexView(postbox: postbox, peerId: peerId)
}
}

View file

@ -67,7 +67,7 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch
disposable.dispose()
}
case let .replyThread(replyThreadMessage):
let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.mentions(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, threadMessageId: replyThreadMessage.messageId, searchQuery: normalizedQuery.isEmpty ? nil : normalizedQuery, updated: { state in
let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.mentions(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, threadMessageId: EngineMessage.Id(peerId: replyThreadMessage.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: replyThreadMessage.threadId)), searchQuery: normalizedQuery.isEmpty ? nil : normalizedQuery, updated: { state in
if case .ready = state.loadingState {
subscriber.putNext((state.list.compactMap { participant in
if participant.peer.isDeleted {

View file

@ -472,7 +472,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) }
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
dict[64088654] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) }
dict[940666592] = { return Api.Message.parse_message($0) }
dict[1992213009] = { return Api.Message.parse_message($0) }
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
dict[721967202] = { return Api.Message.parse_messageService($0) }
dict[-988359047] = { return Api.MessageAction.parse_messageActionBotAllowed($0) }
@ -748,6 +748,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1054465340] = { return Api.RichText.parse_textUnderline($0) }
dict[1009288385] = { return Api.RichText.parse_textUrl($0) }
dict[289586518] = { return Api.SavedContact.parse_savedPhoneContact($0) }
dict[-1115174036] = { return Api.SavedDialog.parse_savedDialog($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) }
@ -939,6 +940,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1538885128] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
dict[-99664734] = { return Api.Update.parse_updatePinnedDialogs($0) }
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
dict[1751942566] = { return Api.Update.parse_updatePinnedSavedDialogs($0) }
dict[-298113238] = { return Api.Update.parse_updatePrivacy($0) }
dict[861169551] = { return Api.Update.parse_updatePtsChanged($0) }
dict[-693004986] = { return Api.Update.parse_updateReadChannelDiscussionInbox($0) }
@ -954,6 +956,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[821314523] = { return Api.Update.parse_updateRecentEmojiStatuses($0) }
dict[1870160884] = { return Api.Update.parse_updateRecentReactions($0) }
dict[-1706939360] = { return Api.Update.parse_updateRecentStickers($0) }
dict[-1364222348] = { return Api.Update.parse_updateSavedDialogPinned($0) }
dict[-1821035490] = { return Api.Update.parse_updateSavedGifs($0) }
dict[1960361625] = { return Api.Update.parse_updateSavedRingtones($0) }
dict[2103604867] = { return Api.Update.parse_updateSentStoryReaction($0) }
@ -1166,6 +1169,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1334846497] = { return Api.messages.Reactions.parse_reactionsNotModified($0) }
dict[-1999405994] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
dict[-130358751] = { return Api.messages.SavedDialogs.parse_savedDialogs($0) }
dict[-1071681560] = { return Api.messages.SavedDialogs.parse_savedDialogsNotModified($0) }
dict[1153080793] = { return Api.messages.SavedDialogs.parse_savedDialogsSlice($0) }
dict[-2069878259] = { return Api.messages.SavedGifs.parse_savedGifs($0) }
dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) }
dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) }
@ -1263,7 +1269,7 @@ public extension Api {
return parser(reader)
}
else {
telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found")
telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found")
return nil
}
}
@ -1745,6 +1751,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.SavedContact:
_1.serialize(buffer, boxed)
case let _1 as Api.SavedDialog:
_1.serialize(buffer, boxed)
case let _1 as Api.SearchResultsCalendarPeriod:
_1.serialize(buffer, boxed)
case let _1 as Api.SearchResultsPosition:
@ -2061,6 +2069,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.messages.RecentStickers:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.SavedDialogs:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.SavedGifs:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.SearchCounter:

View file

@ -424,20 +424,21 @@ public extension Api {
}
public extension Api {
indirect enum Message: TypeConstructorDescription {
case message(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?)
case message(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?)
case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?)
case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction, ttlPeriod: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod):
case .message(let flags, let id, let fromId, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod):
if boxed {
buffer.appendInt32(940666592)
buffer.appendInt32(1992213009)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 8) != 0 {fromId!.serialize(buffer, true)}
peerId.serialize(buffer, true)
if Int(flags) & Int(1 << 28) != 0 {savedPeerId!.serialize(buffer, true)}
if Int(flags) & Int(1 << 2) != 0 {fwdFrom!.serialize(buffer, true)}
if Int(flags) & Int(1 << 11) != 0 {serializeInt64(viaBotId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {replyTo!.serialize(buffer, true)}
@ -490,8 +491,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod):
return ("message", [("flags", flags as Any), ("id", id as Any), ("fromId", fromId as Any), ("peerId", peerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any)])
case .message(let flags, let id, let fromId, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod):
return ("message", [("flags", flags as Any), ("id", id as Any), ("fromId", fromId as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any)])
case .messageEmpty(let flags, let id, let peerId):
return ("messageEmpty", [("flags", flags as Any), ("id", id as Any), ("peerId", peerId as Any)])
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action, let ttlPeriod):
@ -512,79 +513,84 @@ public extension Api {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _5: Api.MessageFwdHeader?
var _5: Api.Peer?
if Int(_1!) & Int(1 << 28) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _6: Api.MessageFwdHeader?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader
_6 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader
} }
var _6: Int64?
if Int(_1!) & Int(1 << 11) != 0 {_6 = reader.readInt64() }
var _7: Api.MessageReplyHeader?
var _7: Int64?
if Int(_1!) & Int(1 << 11) != 0 {_7 = reader.readInt64() }
var _8: Api.MessageReplyHeader?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
_8 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
} }
var _8: Int32?
_8 = reader.readInt32()
var _9: String?
_9 = parseString(reader)
var _10: Api.MessageMedia?
var _9: Int32?
_9 = reader.readInt32()
var _10: String?
_10 = parseString(reader)
var _11: Api.MessageMedia?
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
_10 = Api.parse(reader, signature: signature) as? Api.MessageMedia
_11 = Api.parse(reader, signature: signature) as? Api.MessageMedia
} }
var _11: Api.ReplyMarkup?
var _12: Api.ReplyMarkup?
if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
_12 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
} }
var _12: [Api.MessageEntity]?
var _13: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() {
_12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
_13 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
var _13: Int32?
if Int(_1!) & Int(1 << 10) != 0 {_13 = reader.readInt32() }
var _14: Int32?
if Int(_1!) & Int(1 << 10) != 0 {_14 = reader.readInt32() }
var _15: Api.MessageReplies?
var _15: Int32?
if Int(_1!) & Int(1 << 10) != 0 {_15 = reader.readInt32() }
var _16: Api.MessageReplies?
if Int(_1!) & Int(1 << 23) != 0 {if let signature = reader.readInt32() {
_15 = Api.parse(reader, signature: signature) as? Api.MessageReplies
_16 = Api.parse(reader, signature: signature) as? Api.MessageReplies
} }
var _16: Int32?
if Int(_1!) & Int(1 << 15) != 0 {_16 = reader.readInt32() }
var _17: String?
if Int(_1!) & Int(1 << 16) != 0 {_17 = parseString(reader) }
var _18: Int64?
if Int(_1!) & Int(1 << 17) != 0 {_18 = reader.readInt64() }
var _19: Api.MessageReactions?
var _17: Int32?
if Int(_1!) & Int(1 << 15) != 0 {_17 = reader.readInt32() }
var _18: String?
if Int(_1!) & Int(1 << 16) != 0 {_18 = parseString(reader) }
var _19: Int64?
if Int(_1!) & Int(1 << 17) != 0 {_19 = reader.readInt64() }
var _20: Api.MessageReactions?
if Int(_1!) & Int(1 << 20) != 0 {if let signature = reader.readInt32() {
_19 = Api.parse(reader, signature: signature) as? Api.MessageReactions
_20 = Api.parse(reader, signature: signature) as? Api.MessageReactions
} }
var _20: [Api.RestrictionReason]?
var _21: [Api.RestrictionReason]?
if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() {
_20 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
_21 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
} }
var _21: Int32?
if Int(_1!) & Int(1 << 25) != 0 {_21 = reader.readInt32() }
var _22: Int32?
if Int(_1!) & Int(1 << 25) != 0 {_22 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 11) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
let _c8 = _8 != nil
let _c5 = (Int(_1!) & Int(1 << 28) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
let _c9 = _9 != nil
let _c10 = (Int(_1!) & Int(1 << 9) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 6) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 10) == 0) || _13 != nil
let _c10 = _10 != nil
let _c11 = (Int(_1!) & Int(1 << 9) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 6) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 7) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 10) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 23) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 15) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 16) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 17) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 20) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 22) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 25) == 0) || _21 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 {
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, peerId: _4!, fwdFrom: _5, viaBotId: _6, replyTo: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, forwards: _14, replies: _15, editDate: _16, postAuthor: _17, groupedId: _18, reactions: _19, restrictionReason: _20, ttlPeriod: _21)
let _c15 = (Int(_1!) & Int(1 << 10) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 23) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 15) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 16) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 17) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 20) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 22) == 0) || _21 != nil
let _c22 = (Int(_1!) & Int(1 << 25) == 0) || _22 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 {
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, peerId: _4!, savedPeerId: _5, fwdFrom: _6, viaBotId: _7, replyTo: _8, date: _9!, message: _10!, media: _11, replyMarkup: _12, entities: _13, views: _14, forwards: _15, replies: _16, editDate: _17, postAuthor: _18, groupedId: _19, reactions: _20, restrictionReason: _21, ttlPeriod: _22)
}
else {
return nil

View file

@ -606,6 +606,52 @@ public extension Api {
}
}
public extension Api {
enum SavedDialog: TypeConstructorDescription {
case savedDialog(flags: Int32, peer: Api.Peer, topMessage: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
if boxed {
buffer.appendInt32(-1115174036)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(topMessage, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
return ("savedDialog", [("flags", flags as Any), ("peer", peer as Any), ("topMessage", topMessage as Any)])
}
}
public static func parse_savedDialog(_ reader: BufferReader) -> SavedDialog? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SavedDialog.savedDialog(flags: _1!, peer: _2!, topMessage: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsCalendarPeriod: TypeConstructorDescription {
case searchResultsCalendarPeriod(date: Int32, minMsgId: Int32, maxMsgId: Int32, count: Int32)

View file

@ -550,6 +550,7 @@ public extension Api {
case updatePinnedChannelMessages(flags: Int32, channelId: Int64, messages: [Int32], pts: Int32, ptsCount: Int32)
case updatePinnedDialogs(flags: Int32, folderId: Int32?, order: [Api.DialogPeer]?)
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
case updatePinnedSavedDialogs(flags: Int32, order: [Api.DialogPeer]?)
case updatePrivacy(key: Api.PrivacyKey, rules: [Api.PrivacyRule])
case updatePtsChanged
case updateReadChannelDiscussionInbox(flags: Int32, channelId: Int64, topMsgId: Int32, readMaxId: Int32, broadcastId: Int64?, broadcastPost: Int32?)
@ -565,6 +566,7 @@ public extension Api {
case updateRecentEmojiStatuses
case updateRecentReactions
case updateRecentStickers
case updateSavedDialogPinned(flags: Int32, peer: Api.DialogPeer)
case updateSavedGifs
case updateSavedRingtones
case updateSentStoryReaction(peer: Api.Peer, storyId: Int32, reaction: Api.Reaction)
@ -1372,6 +1374,17 @@ public extension Api {
serializeInt32(pts, buffer: buffer, boxed: false)
serializeInt32(ptsCount, buffer: buffer, boxed: false)
break
case .updatePinnedSavedDialogs(let flags, let order):
if boxed {
buffer.appendInt32(1751942566)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(order!.count))
for item in order! {
item.serialize(buffer, true)
}}
break
case .updatePrivacy(let key, let rules):
if boxed {
buffer.appendInt32(-298113238)
@ -1497,6 +1510,13 @@ public extension Api {
buffer.appendInt32(-1706939360)
}
break
case .updateSavedDialogPinned(let flags, let peer):
if boxed {
buffer.appendInt32(-1364222348)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
break
case .updateSavedGifs:
if boxed {
@ -1828,6 +1848,8 @@ public extension Api {
return ("updatePinnedDialogs", [("flags", flags as Any), ("folderId", folderId as Any), ("order", order as Any)])
case .updatePinnedMessages(let flags, let peer, let messages, let pts, let ptsCount):
return ("updatePinnedMessages", [("flags", flags as Any), ("peer", peer as Any), ("messages", messages as Any), ("pts", pts as Any), ("ptsCount", ptsCount as Any)])
case .updatePinnedSavedDialogs(let flags, let order):
return ("updatePinnedSavedDialogs", [("flags", flags as Any), ("order", order as Any)])
case .updatePrivacy(let key, let rules):
return ("updatePrivacy", [("key", key as Any), ("rules", rules as Any)])
case .updatePtsChanged:
@ -1858,6 +1880,8 @@ public extension Api {
return ("updateRecentReactions", [])
case .updateRecentStickers:
return ("updateRecentStickers", [])
case .updateSavedDialogPinned(let flags, let peer):
return ("updateSavedDialogPinned", [("flags", flags as Any), ("peer", peer as Any)])
case .updateSavedGifs:
return ("updateSavedGifs", [])
case .updateSavedRingtones:
@ -3538,6 +3562,22 @@ public extension Api {
return nil
}
}
public static func parse_updatePinnedSavedDialogs(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.DialogPeer]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DialogPeer.self)
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
if _c1 && _c2 {
return Api.Update.updatePinnedSavedDialogs(flags: _1!, order: _2)
}
else {
return nil
}
}
public static func parse_updatePrivacy(_ reader: BufferReader) -> Update? {
var _1: Api.PrivacyKey?
if let signature = reader.readInt32() {
@ -3751,6 +3791,22 @@ public extension Api {
public static func parse_updateRecentStickers(_ reader: BufferReader) -> Update? {
return Api.Update.updateRecentStickers
}
public static func parse_updateSavedDialogPinned(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.DialogPeer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.DialogPeer
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updateSavedDialogPinned(flags: _1!, peer: _2!)
}
else {
return nil
}
}
public static func parse_updateSavedGifs(_ reader: BufferReader) -> Update? {
return Api.Update.updateSavedGifs
}

View file

@ -1425,59 +1425,153 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum SavedGifs: TypeConstructorDescription {
case savedGifs(hash: Int64, gifs: [Api.Document])
case savedGifsNotModified
enum SavedDialogs: TypeConstructorDescription {
case savedDialogs(dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case savedDialogsNotModified(count: Int32)
case savedDialogsSlice(count: Int32, dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedGifs(let hash, let gifs):
case .savedDialogs(let dialogs, let messages, let chats, let users):
if boxed {
buffer.appendInt32(-2069878259)
buffer.appendInt32(-130358751)
}
serializeInt64(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(gifs.count))
for item in gifs {
buffer.appendInt32(Int32(dialogs.count))
for item in dialogs {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
case .savedGifsNotModified:
case .savedDialogsNotModified(let count):
if boxed {
buffer.appendInt32(-402498398)
buffer.appendInt32(-1071681560)
}
serializeInt32(count, buffer: buffer, boxed: false)
break
case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users):
if boxed {
buffer.appendInt32(1153080793)
}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(dialogs.count))
for item in dialogs {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedGifs(let hash, let gifs):
return ("savedGifs", [("hash", hash as Any), ("gifs", gifs as Any)])
case .savedGifsNotModified:
return ("savedGifsNotModified", [])
case .savedDialogs(let dialogs, let messages, let chats, let users):
return ("savedDialogs", [("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
case .savedDialogsNotModified(let count):
return ("savedDialogsNotModified", [("count", count as Any)])
case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users):
return ("savedDialogsSlice", [("count", count as Any), ("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_savedGifs(_ reader: BufferReader) -> SavedGifs? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [Api.Document]?
public static func parse_savedDialogs(_ reader: BufferReader) -> SavedDialogs? {
var _1: [Api.SavedDialog]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self)
}
var _2: [Api.Message]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _3: [Api.Chat]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SavedGifs.savedGifs(hash: _1!, gifs: _2!)
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.messages.SavedDialogs.savedDialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!)
}
else {
return nil
}
}
public static func parse_savedGifsNotModified(_ reader: BufferReader) -> SavedGifs? {
return Api.messages.SavedGifs.savedGifsNotModified
public static func parse_savedDialogsNotModified(_ reader: BufferReader) -> SavedDialogs? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.messages.SavedDialogs.savedDialogsNotModified(count: _1!)
}
else {
return nil
}
}
public static func parse_savedDialogsSlice(_ reader: BufferReader) -> SavedDialogs? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.SavedDialog]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self)
}
var _3: [Api.Message]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _4: [Api.Chat]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.messages.SavedDialogs.savedDialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!)
}
else {
return nil
}
}
}

View file

@ -1,3 +1,61 @@
public extension Api.messages {
enum SavedGifs: TypeConstructorDescription {
case savedGifs(hash: Int64, gifs: [Api.Document])
case savedGifsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedGifs(let hash, let gifs):
if boxed {
buffer.appendInt32(-2069878259)
}
serializeInt64(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(gifs.count))
for item in gifs {
item.serialize(buffer, true)
}
break
case .savedGifsNotModified:
if boxed {
buffer.appendInt32(-402498398)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedGifs(let hash, let gifs):
return ("savedGifs", [("hash", hash as Any), ("gifs", gifs as Any)])
case .savedGifsNotModified:
return ("savedGifsNotModified", [])
}
}
public static func parse_savedGifs(_ reader: BufferReader) -> SavedGifs? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [Api.Document]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SavedGifs.savedGifs(hash: _1!, gifs: _2!)
}
else {
return nil
}
}
public static func parse_savedGifsNotModified(_ reader: BufferReader) -> SavedGifs? {
return Api.messages.SavedGifs.savedGifsNotModified
}
}
}
public extension Api.messages {
enum SearchCounter: TypeConstructorDescription {
case searchCounter(flags: Int32, filter: Api.MessagesFilter, count: Int32)
@ -1482,85 +1540,3 @@ public extension Api.phone {
}
}
public extension Api.phone {
enum GroupCallStreamChannels: TypeConstructorDescription {
case groupCallStreamChannels(channels: [Api.GroupCallStreamChannel])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallStreamChannels(let channels):
if boxed {
buffer.appendInt32(-790330702)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(channels.count))
for item in channels {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallStreamChannels(let channels):
return ("groupCallStreamChannels", [("channels", channels as Any)])
}
}
public static func parse_groupCallStreamChannels(_ reader: BufferReader) -> GroupCallStreamChannels? {
var _1: [Api.GroupCallStreamChannel]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallStreamChannel.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.phone.GroupCallStreamChannels.groupCallStreamChannels(channels: _1!)
}
else {
return nil
}
}
}
}
public extension Api.phone {
enum GroupCallStreamRtmpUrl: TypeConstructorDescription {
case groupCallStreamRtmpUrl(url: String, key: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallStreamRtmpUrl(let url, let key):
if boxed {
buffer.appendInt32(767505458)
}
serializeString(url, buffer: buffer, boxed: false)
serializeString(key, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallStreamRtmpUrl(let url, let key):
return ("groupCallStreamRtmpUrl", [("url", url as Any), ("key", key as Any)])
}
}
public static func parse_groupCallStreamRtmpUrl(_ reader: BufferReader) -> GroupCallStreamRtmpUrl? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.phone.GroupCallStreamRtmpUrl.groupCallStreamRtmpUrl(url: _1!, key: _2!)
}
else {
return nil
}
}
}
}

View file

@ -1,3 +1,85 @@
public extension Api.phone {
enum GroupCallStreamChannels: TypeConstructorDescription {
case groupCallStreamChannels(channels: [Api.GroupCallStreamChannel])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallStreamChannels(let channels):
if boxed {
buffer.appendInt32(-790330702)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(channels.count))
for item in channels {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallStreamChannels(let channels):
return ("groupCallStreamChannels", [("channels", channels as Any)])
}
}
public static func parse_groupCallStreamChannels(_ reader: BufferReader) -> GroupCallStreamChannels? {
var _1: [Api.GroupCallStreamChannel]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallStreamChannel.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.phone.GroupCallStreamChannels.groupCallStreamChannels(channels: _1!)
}
else {
return nil
}
}
}
}
public extension Api.phone {
enum GroupCallStreamRtmpUrl: TypeConstructorDescription {
case groupCallStreamRtmpUrl(url: String, key: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallStreamRtmpUrl(let url, let key):
if boxed {
buffer.appendInt32(767505458)
}
serializeString(url, buffer: buffer, boxed: false)
serializeString(key, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallStreamRtmpUrl(let url, let key):
return ("groupCallStreamRtmpUrl", [("url", url as Any), ("key", key as Any)])
}
}
public static func parse_groupCallStreamRtmpUrl(_ reader: BufferReader) -> GroupCallStreamRtmpUrl? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.phone.GroupCallStreamRtmpUrl.groupCallStreamRtmpUrl(url: _1!, key: _2!)
}
else {
return nil
}
}
}
}
public extension Api.phone {
enum GroupParticipants: TypeConstructorDescription {
case groupParticipants(count: Int32, participants: [Api.GroupCallParticipant], nextOffset: String, chats: [Api.Chat], users: [Api.User], version: Int32)
@ -1494,141 +1576,3 @@ public extension Api.stories {
}
}
public extension Api.stories {
enum StoryViews: TypeConstructorDescription {
case storyViews(views: [Api.StoryViews], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViews(let views, let users):
if boxed {
buffer.appendInt32(-560009955)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViews(let views, let users):
return ("storyViews", [("views", views as Any), ("users", users as Any)])
}
}
public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? {
var _1: [Api.StoryViews]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryViews.self)
}
var _2: [Api.User]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.stories.StoryViews.storyViews(views: _1!, users: _2!)
}
else {
return nil
}
}
}
}
public extension Api.stories {
enum StoryViewsList: TypeConstructorDescription {
case storyViewsList(flags: Int32, count: Int32, viewsCount: Int32, forwardsCount: Int32, reactionsCount: Int32, views: [Api.StoryView], chats: [Api.Chat], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset):
if boxed {
buffer.appendInt32(1507299269)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt32(viewsCount, buffer: buffer, boxed: false)
serializeInt32(forwardsCount, buffer: buffer, boxed: false)
serializeInt32(reactionsCount, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset):
return ("storyViewsList", [("flags", flags as Any), ("count", count as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactionsCount", reactionsCount as Any), ("views", views as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
}
}
public static func parse_storyViewsList(_ reader: BufferReader) -> StoryViewsList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: [Api.StoryView]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryView.self)
}
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _8: [Api.User]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _9: String?
if Int(_1!) & Int(1 << 0) != 0 {_9 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.stories.StoryViewsList.storyViewsList(flags: _1!, count: _2!, viewsCount: _3!, forwardsCount: _4!, reactionsCount: _5!, views: _6!, chats: _7!, users: _8!, nextOffset: _9)
}
else {
return nil
}
}
}
}

View file

@ -1,3 +1,141 @@
public extension Api.stories {
enum StoryViews: TypeConstructorDescription {
case storyViews(views: [Api.StoryViews], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViews(let views, let users):
if boxed {
buffer.appendInt32(-560009955)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViews(let views, let users):
return ("storyViews", [("views", views as Any), ("users", users as Any)])
}
}
public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? {
var _1: [Api.StoryViews]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryViews.self)
}
var _2: [Api.User]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.stories.StoryViews.storyViews(views: _1!, users: _2!)
}
else {
return nil
}
}
}
}
public extension Api.stories {
enum StoryViewsList: TypeConstructorDescription {
case storyViewsList(flags: Int32, count: Int32, viewsCount: Int32, forwardsCount: Int32, reactionsCount: Int32, views: [Api.StoryView], chats: [Api.Chat], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset):
if boxed {
buffer.appendInt32(1507299269)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt32(viewsCount, buffer: buffer, boxed: false)
serializeInt32(forwardsCount, buffer: buffer, boxed: false)
serializeInt32(reactionsCount, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset):
return ("storyViewsList", [("flags", flags as Any), ("count", count as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactionsCount", reactionsCount as Any), ("views", views as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
}
}
public static func parse_storyViewsList(_ reader: BufferReader) -> StoryViewsList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: [Api.StoryView]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryView.self)
}
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _8: [Api.User]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _9: String?
if Int(_1!) & Int(1 << 0) != 0 {_9 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.stories.StoryViewsList.storyViewsList(flags: _1!, count: _2!, viewsCount: _3!, forwardsCount: _4!, reactionsCount: _5!, views: _6!, chats: _7!, users: _8!, nextOffset: _9)
}
else {
return nil
}
}
}
}
public extension Api.updates {
indirect enum ChannelDifference: TypeConstructorDescription {
case channelDifference(flags: Int32, pts: Int32, timeout: Int32?, newMessages: [Api.Message], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User])

View file

@ -5670,6 +5670,21 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func getPinnedSavedDialogs() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SavedDialogs>) {
let buffer = Buffer()
buffer.appendInt32(-700607264)
return (FunctionDescription(name: "messages.getPinnedSavedDialogs", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SavedDialogs? in
let reader = BufferReader(buffer)
var result: Api.messages.SavedDialogs?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SavedDialogs
}
return result
})
}
}
public extension Api.functions.messages {
static func getPollResults(peer: Api.InputPeer, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
@ -5778,6 +5793,26 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func getSavedDialogs(flags: Int32, offsetDate: Int32, offsetId: Int32, offsetPeer: Api.InputPeer, limit: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SavedDialogs>) {
let buffer = Buffer()
buffer.appendInt32(1401016858)
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(offsetDate, buffer: buffer, boxed: false)
serializeInt32(offsetId, buffer: buffer, boxed: false)
offsetPeer.serialize(buffer, true)
serializeInt32(limit, buffer: buffer, boxed: false)
serializeInt64(hash, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSavedDialogs", parameters: [("flags", String(describing: flags)), ("offsetDate", String(describing: offsetDate)), ("offsetId", String(describing: offsetId)), ("offsetPeer", String(describing: offsetPeer)), ("limit", String(describing: limit)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SavedDialogs? in
let reader = BufferReader(buffer)
var result: Api.messages.SavedDialogs?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SavedDialogs
}
return result
})
}
}
public extension Api.functions.messages {
static func getSavedGifs(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SavedGifs>) {
let buffer = Buffer()
@ -5793,6 +5828,28 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func getSavedHistory(peer: Api.InputPeer, offsetId: Int32, offsetDate: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) {
let buffer = Buffer()
buffer.appendInt32(1033519437)
peer.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(offsetDate, buffer: buffer, boxed: false)
serializeInt32(addOffset, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false)
serializeInt32(maxId, buffer: buffer, boxed: false)
serializeInt32(minId, buffer: buffer, boxed: false)
serializeInt64(hash, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSavedHistory", parameters: [("peer", String(describing: peer)), ("offsetId", String(describing: offsetId)), ("offsetDate", String(describing: offsetDate)), ("addOffset", String(describing: addOffset)), ("limit", String(describing: limit)), ("maxId", String(describing: maxId)), ("minId", String(describing: minId)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in
let reader = BufferReader(buffer)
var result: Api.messages.Messages?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.Messages
}
return result
})
}
}
public extension Api.functions.messages {
static func getScheduledHistory(peer: Api.InputPeer, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) {
let buffer = Buffer()
@ -5830,18 +5887,19 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func getSearchCounters(flags: Int32, peer: Api.InputPeer, topMsgId: Int32?, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
static func getSearchCounters(flags: Int32, peer: Api.InputPeer, savedPeerId: Api.InputPeer?, topMsgId: Int32?, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) {
let buffer = Buffer()
buffer.appendInt32(11435201)
buffer.appendInt32(465367808)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {savedPeerId!.serialize(buffer, true)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(filters.count))
for item in filters {
item.serialize(buffer, true)
}
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("topMsgId", String(describing: topMsgId)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("savedPeerId", String(describing: savedPeerId)), ("topMsgId", String(describing: topMsgId)), ("filters", String(describing: filters))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in
let reader = BufferReader(buffer)
var result: [Api.messages.SearchCounter]?
if let _ = reader.readInt32() {
@ -5852,14 +5910,16 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func getSearchResultsCalendar(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, offsetDate: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsCalendar>) {
static func getSearchResultsCalendar(flags: Int32, peer: Api.InputPeer, savedPeerId: Api.InputPeer?, filter: Api.MessagesFilter, offsetId: Int32, offsetDate: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsCalendar>) {
let buffer = Buffer()
buffer.appendInt32(1240514025)
buffer.appendInt32(1789130429)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {savedPeerId!.serialize(buffer, true)}
filter.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(offsetDate, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSearchResultsCalendar", parameters: [("peer", String(describing: peer)), ("filter", String(describing: filter)), ("offsetId", String(describing: offsetId)), ("offsetDate", String(describing: offsetDate))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsCalendar? in
return (FunctionDescription(name: "messages.getSearchResultsCalendar", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("savedPeerId", String(describing: savedPeerId)), ("filter", String(describing: filter)), ("offsetId", String(describing: offsetId)), ("offsetDate", String(describing: offsetDate))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsCalendar? in
let reader = BufferReader(buffer)
var result: Api.messages.SearchResultsCalendar?
if let signature = reader.readInt32() {
@ -5870,14 +5930,16 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func getSearchResultsPositions(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsPositions>) {
static func getSearchResultsPositions(flags: Int32, peer: Api.InputPeer, savedPeerId: Api.InputPeer?, filter: Api.MessagesFilter, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsPositions>) {
let buffer = Buffer()
buffer.appendInt32(1855292323)
buffer.appendInt32(-1669386480)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {savedPeerId!.serialize(buffer, true)}
filter.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSearchResultsPositions", parameters: [("peer", String(describing: peer)), ("filter", String(describing: filter)), ("offsetId", String(describing: offsetId)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsPositions? in
return (FunctionDescription(name: "messages.getSearchResultsPositions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("savedPeerId", String(describing: savedPeerId)), ("filter", String(describing: filter)), ("offsetId", String(describing: offsetId)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsPositions? in
let reader = BufferReader(buffer)
var result: Api.messages.SearchResultsPositions?
if let signature = reader.readInt32() {
@ -6384,6 +6446,26 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func reorderPinnedSavedDialogs(flags: Int32, order: [Api.InputDialogPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-1955502713)
serializeInt32(flags, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(order.count))
for item in order {
item.serialize(buffer, true)
}
return (FunctionDescription(name: "messages.reorderPinnedSavedDialogs", parameters: [("flags", String(describing: flags)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.messages {
static func reorderStickerSets(flags: Int32, order: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -6646,13 +6728,14 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func search(flags: Int32, peer: Api.InputPeer, q: String, fromId: Api.InputPeer?, topMsgId: Int32?, filter: Api.MessagesFilter, minDate: Int32, maxDate: Int32, offsetId: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) {
static func search(flags: Int32, peer: Api.InputPeer, q: String, fromId: Api.InputPeer?, savedPeerId: Api.InputPeer?, topMsgId: Int32?, filter: Api.MessagesFilter, minDate: Int32, maxDate: Int32, offsetId: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) {
let buffer = Buffer()
buffer.appendInt32(-1593989278)
buffer.appendInt32(-1481316055)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeString(q, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {fromId!.serialize(buffer, true)}
if Int(flags) & Int(1 << 2) != 0 {savedPeerId!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)}
filter.serialize(buffer, true)
serializeInt32(minDate, buffer: buffer, boxed: false)
@ -6663,7 +6746,7 @@ public extension Api.functions.messages {
serializeInt32(maxId, buffer: buffer, boxed: false)
serializeInt32(minId, buffer: buffer, boxed: false)
serializeInt64(hash, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.search", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("q", String(describing: q)), ("fromId", String(describing: fromId)), ("topMsgId", String(describing: topMsgId)), ("filter", String(describing: filter)), ("minDate", String(describing: minDate)), ("maxDate", String(describing: maxDate)), ("offsetId", String(describing: offsetId)), ("addOffset", String(describing: addOffset)), ("limit", String(describing: limit)), ("maxId", String(describing: maxId)), ("minId", String(describing: minId)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in
return (FunctionDescription(name: "messages.search", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("q", String(describing: q)), ("fromId", String(describing: fromId)), ("savedPeerId", String(describing: savedPeerId)), ("topMsgId", String(describing: topMsgId)), ("filter", String(describing: filter)), ("minDate", String(describing: minDate)), ("maxDate", String(describing: maxDate)), ("offsetId", String(describing: offsetId)), ("addOffset", String(describing: addOffset)), ("limit", String(describing: limit)), ("maxId", String(describing: maxId)), ("minId", String(describing: minId)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in
let reader = BufferReader(buffer)
var result: Api.messages.Messages?
if let signature = reader.readInt32() {
@ -7405,6 +7488,22 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func toggleSavedDialogPin(flags: Int32, peer: Api.InputDialogPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-1400783906)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.toggleSavedDialogPin", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.messages {
static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View file

@ -126,7 +126,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
switch messsage {
case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
let chatPeerId = messagePeerId
return chatPeerId.peerId
case let .messageEmpty(_, _, peerId):
@ -142,7 +142,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
switch message {
case let .message(_, _, fromId, chatPeerId, fwdHeader, viaBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _):
case let .message(_, _, fromId, chatPeerId, savedPeerId, fwdHeader, viaBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _):
let peerId: PeerId = chatPeerId.peerId
var result = [peerId]
@ -168,6 +168,10 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
if let viaBotId = viaBotId {
result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(viaBotId)))
}
if let savedPeerId = savedPeerId {
result.append(savedPeerId.peerId)
}
if let media = media {
switch media {
@ -256,7 +260,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? {
switch message {
case let .message(_, id, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, id, _, chatPeerId, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
if let replyTo = replyTo {
let peerId: PeerId = chatPeerId.peerId
@ -582,7 +586,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage {
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
switch apiMessage {
case let .message(flags, id, fromId, chatPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod):
case let .message(flags, id, fromId, chatPeerId, savedPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod):
let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId
let peerId: PeerId
@ -622,17 +626,17 @@ extension StoreMessage {
if isForumTopic {
let threadIdValue = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToTopId)
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
} else {
if peerId.namespace == Namespaces.Peer.CloudChannel {
let threadIdValue = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToTopId)
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
} else {
let threadIdValue = MessageId(peerId: replyToPeerId?.peerId ?? peerId, namespace: Namespaces.Message.Cloud, id: replyToTopId)
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
}
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
@ -641,11 +645,11 @@ extension StoreMessage {
if peerIsForum {
if isForumTopic {
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
} else {
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
}
attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId), threadMessageId: threadMessageId, quote: quote, isQuote: isQuote))
@ -663,7 +667,6 @@ extension StoreMessage {
}
var forwardInfo: StoreMessageForwardInfo?
var savedFromPeerId: PeerId?
if let fwdFrom = fwdFrom {
switch fwdFrom {
case let .messageFwdHeader(flags, fromId, fromName, date, channelPost, postAuthor, savedFromPeer, savedFromMsgId, psaType):
@ -693,7 +696,6 @@ extension StoreMessage {
if let savedFromPeer = savedFromPeer, let savedFromMsgId = savedFromMsgId {
let peerId: PeerId = savedFromPeer.peerId
savedFromPeerId = peerId
let messageId: MessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: savedFromMsgId)
attributes.append(SourceReferenceMessageAttribute(messageId: messageId))
}
@ -708,8 +710,8 @@ extension StoreMessage {
}
}
if peerId == accountPeerId, let savedFromPeerId = savedFromPeerId {
threadId = savedFromPeerId.toInt64()
if peerId == accountPeerId, let savedPeerId = savedPeerId {
threadId = savedPeerId.peerId.toInt64()
}
let messageText = message
@ -911,12 +913,12 @@ extension StoreMessage {
let threadIdValue = MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToTopId)
threadMessageId = threadIdValue
if replyPeerId == peerId {
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
let threadIdValue = MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)
threadMessageId = threadIdValue
threadId = makeMessageThreadId(threadIdValue)
threadId = Int64(threadIdValue.id)
}
switch action {
case .messageActionTopicEdit:

View file

@ -516,7 +516,7 @@ func _internal_setChannelForumMode(postbox: Postbox, network: Network, stateMana
struct LoadMessageHistoryThreadsResult {
struct Item {
var threadId: Int64
var data: MessageHistoryThreadData
var data: MessageHistoryThreadData?
var topMessage: Int32
var unreadMentionsCount: Int32
var unreadReactionsCount: Int32
@ -524,7 +524,7 @@ struct LoadMessageHistoryThreadsResult {
init(
threadId: Int64,
data: MessageHistoryThreadData,
data: MessageHistoryThreadData?,
topMessage: Int32,
unreadMentionsCount: Int32,
unreadReactionsCount: Int32,
@ -570,95 +570,172 @@ enum LoadMessageHistoryThreadsError {
case generic
}
func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Postbox, network: Network, peerId: PeerId, query: String?, offsetIndex: StoredPeerThreadCombinedState.Index?, limit: Int) -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> {
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = postbox.transaction { transaction -> Api.InputChannel? in
guard let channel = transaction.getPeer(peerId) as? TelegramChannel else {
return nil
}
if !channel.flags.contains(.isForum) {
return nil
}
return apiInputChannel(channel)
func _internal_fillSavedMessageHistory(accountPeerId: PeerId, postbox: Postbox, network: Network) -> Signal<Never, NoError> {
enum PassResult {
case restart
}
|> castError(LoadMessageHistoryThreadsError.self)
|> mapToSignal { inputChannel -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> in
guard let inputChannel = inputChannel else {
return .fail(.generic)
return (postbox.transaction { transaction -> Range<Int>? in
let holes = transaction.getHoles(peerId: accountPeerId, namespace: Namespaces.Message.Cloud)
return holes.rangeView.last
}
|> castError(PassResult.self)
|> mapToSignal { range -> Signal<Never, PassResult> in
if let range {
return fetchMessageHistoryHole(
accountPeerId: accountPeerId,
source: .network(network),
postbox: postbox,
peerInput: .direct(peerId: accountPeerId, threadId: nil),
namespace: Namespaces.Message.Cloud,
direction: .range(
start: MessageId(peerId: accountPeerId, namespace: Namespaces.Message.Cloud, id: Int32(range.upperBound) - 1),
end: MessageId(peerId: accountPeerId, namespace: Namespaces.Message.Cloud, id: Int32(range.lowerBound) - 1)
),
space: .everywhere,
count: 100
)
|> ignoreValues
|> castError(PassResult.self)
|> then(.fail(.restart))
} else {
return .complete()
}
})
|> restartIfError
}
func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Postbox, network: Network, peerId: PeerId, query: String?, offsetIndex: StoredPeerThreadCombinedState.Index?, limit: Int) -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> {
if peerId == accountPeerId {
if !"".isEmpty {
return _internal_fillSavedMessageHistory(accountPeerId: accountPeerId, postbox: postbox, network: network)
|> castError(LoadMessageHistoryThreadsError.self)
|> map { _ -> LoadMessageHistoryThreadsResult in
}
|> then(postbox.transaction { transaction -> LoadMessageHistoryThreadsResult in
var topMessages: [Int64: Message] = [:]
transaction.scanTopMessages(peerId: accountPeerId, namespace: Namespaces.Message.Cloud, limit: 100000, { message in
if let threadId = message.threadId {
if let current = topMessages[threadId] {
if current.id < message.id {
topMessages[threadId] = message
}
} else {
topMessages[threadId] = message
}
}
return true
})
var items: [LoadMessageHistoryThreadsResult.Item] = []
for message in topMessages.values.sorted(by: { $0.id > $1.id }) {
guard let threadId = message.threadId else {
continue
}
items.append(LoadMessageHistoryThreadsResult.Item(
threadId: threadId,
data: MessageHistoryThreadData(
creationDate: 0,
isOwnedByMe: true,
author: accountPeerId,
info: EngineMessageHistoryThread.Info(title: "", icon: nil, iconColor: 0),
incomingUnreadCount: 0,
maxIncomingReadId: 0,
maxKnownMessageId: 0,
maxOutgoingReadId: 0,
isClosed: false,
isHidden: false,
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
),
topMessage: message.id.id,
unreadMentionsCount: 0,
unreadReactionsCount: 0,
index: StoredPeerThreadCombinedState.Index(timestamp: message.timestamp, threadId: threadId, messageId: message.id.id)
))
}
return LoadMessageHistoryThreadsResult(
peerId: accountPeerId,
items: items,
messages: [],
pinnedThreadIds: nil,
combinedState: PeerThreadCombinedState(validIndexBoundary: StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)),
users: [],
chats: []
)
}
|> castError(LoadMessageHistoryThreadsError.self))
}
var flags: Int32 = 0
if query != nil {
flags |= 1 << 0
}
var flags: Int32 = 0
flags = 0
var offsetDate: Int32 = 0
var offsetId: Int32 = 0
var offsetTopic: Int32 = 0
var offsetPeer: Api.InputPeer = .inputPeerEmpty
if let offsetIndex = offsetIndex {
offsetDate = offsetIndex.timestamp
offsetId = offsetIndex.messageId
offsetTopic = Int32(clamping: offsetIndex.threadId)
//TODO:api
offsetPeer = .inputPeerEmpty
}
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = network.request(Api.functions.channels.getForumTopics(
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = network.request(Api.functions.messages.getSavedDialogs(
flags: flags,
channel: inputChannel,
q: query,
offsetDate: offsetDate,
offsetId: offsetId,
offsetTopic: offsetTopic,
limit: Int32(limit)
offsetPeer: offsetPeer,
limit: Int32(limit),
hash: 0
))
|> mapError { _ -> LoadMessageHistoryThreadsError in
return .generic
}
|> mapToSignal { result -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> in
switch result {
case let .forumTopics(_, _, topics, messages, chats, users, pts):
case .savedDialogs(let dialogs, let messages, let chats, let users), .savedDialogsSlice(_, let dialogs, let messages, let chats, let users):
var items: [LoadMessageHistoryThreadsResult.Item] = []
var pinnedIds: [Int64] = []
let addedMessages = messages.compactMap { message -> StoreMessage? in
return StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: true)
return StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: false)
}
let _ = pts
var minIndex: StoredPeerThreadCombinedState.Index?
for topic in topics {
switch topic {
case let .forumTopic(flags, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings, draft):
let _ = draft
if (flags & (1 << 3)) != 0 {
pinnedIds.append(Int64(id))
for dialog in dialogs {
switch dialog {
case let .savedDialog(flags, peer, topMessage):
if (flags & (1 << 2)) != 0 {
pinnedIds.append(peer.peerId.toInt64())
}
let data = MessageHistoryThreadData(
creationDate: date,
isOwnedByMe: (flags & (1 << 1)) != 0,
author: fromId.peerId,
creationDate: 0,
isOwnedByMe: true,
author: peer.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
title: "",
icon: nil,
iconColor: 0
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
incomingUnreadCount: 0,
maxIncomingReadId: 0,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
isClosed: (flags & (1 << 2)) != 0,
isHidden: (flags & (1 << 6)) != 0,
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
maxOutgoingReadId: 0,
isClosed: false,
isHidden: false,
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
)
var topTimestamp = date
var topTimestamp: Int32 = 1
for message in addedMessages {
if message.id.peerId == peerId && message.threadId == Int64(id) {
if message.id.peerId == peerId && message.threadId == peer.peerId.toInt64() {
topTimestamp = max(topTimestamp, message.timestamp)
}
}
let topicIndex = StoredPeerThreadCombinedState.Index(timestamp: topTimestamp, threadId: Int64(id), messageId: topMessage)
let topicIndex = StoredPeerThreadCombinedState.Index(timestamp: topTimestamp, threadId: peer.peerId.toInt64(), messageId: topMessage)
if let minIndexValue = minIndex {
if topicIndex < minIndexValue {
minIndex = topicIndex
@ -668,15 +745,13 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
}
items.append(LoadMessageHistoryThreadsResult.Item(
threadId: Int64(id),
threadId: peer.peerId.toInt64(),
data: data,
topMessage: topMessage,
unreadMentionsCount: unreadMentionsCount,
unreadReactionsCount: unreadReactionsCount,
unreadMentionsCount: 0,
unreadReactionsCount: 0,
index: topicIndex
))
case .forumTopicDeleted:
break
}
}
@ -686,7 +761,7 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
}
var nextIndex: StoredPeerThreadCombinedState.Index
if topics.count != 0 {
if dialogs.count != 0 {
nextIndex = minIndex ?? StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)
} else {
nextIndex = StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)
@ -706,12 +781,154 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
users: users,
chats: chats
))
case .savedDialogsNotModified:
return .complete()
}
}
return signal
} else {
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = postbox.transaction { transaction -> Api.InputChannel? in
guard let channel = transaction.getPeer(peerId) as? TelegramChannel else {
return nil
}
if !channel.flags.contains(.isForum) {
return nil
}
return apiInputChannel(channel)
}
|> castError(LoadMessageHistoryThreadsError.self)
|> mapToSignal { inputChannel -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> in
guard let inputChannel = inputChannel else {
return .fail(.generic)
}
var flags: Int32 = 0
if query != nil {
flags |= 1 << 0
}
var offsetDate: Int32 = 0
var offsetId: Int32 = 0
var offsetTopic: Int32 = 0
if let offsetIndex = offsetIndex {
offsetDate = offsetIndex.timestamp
offsetId = offsetIndex.messageId
offsetTopic = Int32(clamping: offsetIndex.threadId)
}
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = network.request(Api.functions.channels.getForumTopics(
flags: flags,
channel: inputChannel,
q: query,
offsetDate: offsetDate,
offsetId: offsetId,
offsetTopic: offsetTopic,
limit: Int32(limit)
))
|> mapError { _ -> LoadMessageHistoryThreadsError in
return .generic
}
|> mapToSignal { result -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> in
switch result {
case let .forumTopics(_, _, topics, messages, chats, users, pts):
var items: [LoadMessageHistoryThreadsResult.Item] = []
var pinnedIds: [Int64] = []
let addedMessages = messages.compactMap { message -> StoreMessage? in
return StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: true)
}
let _ = pts
var minIndex: StoredPeerThreadCombinedState.Index?
for topic in topics {
switch topic {
case let .forumTopic(flags, id, date, title, iconColor, iconEmojiId, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, fromId, notifySettings, draft):
let _ = draft
if (flags & (1 << 3)) != 0 {
pinnedIds.append(Int64(id))
}
let data = MessageHistoryThreadData(
creationDate: date,
isOwnedByMe: (flags & (1 << 1)) != 0,
author: fromId.peerId,
info: EngineMessageHistoryThread.Info(
title: title,
icon: iconEmojiId == 0 ? nil : iconEmojiId,
iconColor: iconColor
),
incomingUnreadCount: unreadCount,
maxIncomingReadId: readInboxMaxId,
maxKnownMessageId: topMessage,
maxOutgoingReadId: readOutboxMaxId,
isClosed: (flags & (1 << 2)) != 0,
isHidden: (flags & (1 << 6)) != 0,
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
)
var topTimestamp = date
for message in addedMessages {
if message.id.peerId == peerId && message.threadId == Int64(id) {
topTimestamp = max(topTimestamp, message.timestamp)
}
}
let topicIndex = StoredPeerThreadCombinedState.Index(timestamp: topTimestamp, threadId: Int64(id), messageId: topMessage)
if let minIndexValue = minIndex {
if topicIndex < minIndexValue {
minIndex = topicIndex
}
} else {
minIndex = topicIndex
}
items.append(LoadMessageHistoryThreadsResult.Item(
threadId: Int64(id),
data: data,
topMessage: topMessage,
unreadMentionsCount: unreadMentionsCount,
unreadReactionsCount: unreadReactionsCount,
index: topicIndex
))
case .forumTopicDeleted:
break
}
}
var pinnedThreadIds: [Int64]?
if offsetIndex == nil {
pinnedThreadIds = pinnedIds
}
var nextIndex: StoredPeerThreadCombinedState.Index
if topics.count != 0 {
nextIndex = minIndex ?? StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)
} else {
nextIndex = StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)
}
if let offsetIndex = offsetIndex, nextIndex == offsetIndex {
nextIndex = StoredPeerThreadCombinedState.Index(timestamp: 0, threadId: 0, messageId: 1)
}
let combinedState = PeerThreadCombinedState(validIndexBoundary: nextIndex)
return .single(LoadMessageHistoryThreadsResult(
peerId: peerId,
items: items,
messages: addedMessages,
pinnedThreadIds: pinnedThreadIds,
combinedState: combinedState,
users: users,
chats: chats
))
}
}
return signal
}
return signal
}
return signal
}
func applyLoadMessageHistoryThreadsResults(accountPeerId: PeerId, transaction: Transaction, results: [LoadMessageHistoryThreadsResult]) {
@ -722,9 +939,16 @@ func applyLoadMessageHistoryThreadsResults(accountPeerId: PeerId, transaction: T
let _ = InternalAccountState.addMessages(transaction: transaction, messages: result.messages, location: .Random)
for item in result.items {
guard let info = StoredMessageHistoryThreadInfo(item.data) else {
let info: StoredMessageHistoryThreadInfo?
if let data = item.data {
info = StoredMessageHistoryThreadInfo(data)
} else {
info = telegramPostboxSeedConfiguration.automaticThreadIndexInfo(result.peerId, item.threadId)
}
guard let info else {
continue
}
transaction.setMessageHistoryThreadInfo(peerId: result.peerId, threadId: item.threadId, info: info)
transaction.replaceMessageTagSummary(peerId: result.peerId, threadId: item.threadId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: item.unreadMentionsCount, maxId: item.topMessage)
@ -864,6 +1088,9 @@ public func _internal_searchForumTopics(account: Account, peerId: EnginePeer.Id,
guard let index = item.index else {
continue
}
guard let itemData = item.data else {
continue
}
items.append(EngineChatList.Item(
id: .forum(item.threadId),
index: .forum(pinnedIndex: .none, timestamp: index.timestamp, threadId: index.threadId, namespace: Namespaces.Message.Cloud, id: index.messageId),
@ -878,10 +1105,10 @@ public func _internal_searchForumTopics(account: Account, peerId: EnginePeer.Id,
hasUnseenReactions: false,
forumTopicData: EngineChatList.ForumTopicData(
id: item.threadId,
title: item.data.info.title,
iconFileId: item.data.info.icon,
iconColor: item.data.info.iconColor,
maxOutgoingReadMessageId: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: item.data.maxOutgoingReadId),
title: itemData.info.title,
iconFileId: itemData.info.icon,
iconColor: itemData.info.iconColor,
maxOutgoingReadMessageId: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: itemData.maxOutgoingReadId),
isUnread: false
),
topForumTopicItems: [],

View file

@ -573,7 +573,9 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
var quote = replyToMessageId.quote
let isQuote = quote != nil
if let replyMessage = transaction.getMessage(replyToMessageId.messageId) {
threadMessageId = replyMessage.effectiveReplyThreadMessageId
if replyMessage.id.namespace == Namespaces.Message.Cloud, let threadId = replyMessage.threadId {
threadMessageId = MessageId(peerId: replyMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))
}
if quote == nil, replyToMessageId.messageId.peerId != peerId {
let nsText = replyMessage.text as NSString
var replyMedia: Media?
@ -712,14 +714,14 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
threadId = threadIdValue
} else {
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
threadId = makeMessageThreadId(replyToMessageId.messageId)
threadId = Int64(replyToMessageId.messageId.id)
}
}
} else {
threadId = threadIdValue
}
} else if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
threadId = makeMessageThreadId(replyToMessageId.messageId)
threadId = Int64(replyToMessageId.messageId.id)
}
}
}
@ -902,7 +904,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
} else if let attribute = attribute as? ReplyMessageAttribute {
if let threadMessageId = attribute.threadMessageId {
threadId = makeMessageThreadId(threadMessageId)
threadId = Int64(threadMessageId.id)
}
} else if let attribute = attribute as? SendAsMessageAttribute {
if let peer = transaction.getPeer(attribute.peerId) {

View file

@ -320,7 +320,7 @@ private func sendUploadedMessageContent(
var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
var messageEntities: [Api.MessageEntity]?
var replyMessageId: Int32? = threadId.flatMap { threadId in
makeThreadIdMessageId(peerId: peerId, threadId: threadId).id
return Int32(clamping: threadId)
}
var replyToStoryId: StoryId?
var scheduleTime: Int32?

View file

@ -1444,7 +1444,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
case let .updateChannelUserTyping(_, channelId, topMsgId, userId, type):
if let date = updatesDate, date + 60 > serverTime {
let channelPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
let threadId = topMsgId.flatMap { makeMessageThreadId(MessageId(peerId: channelPeerId, namespace: Namespaces.Message.Cloud, id: $0)) }
let threadId = topMsgId.flatMap { Int64($0) }
let activity = PeerInputActivity(apiType: type, peerId: nil, timestamp: date)
var category: PeerActivitySpace.Category = .global
@ -3480,16 +3480,16 @@ func replayFinalState(
var removedCount: Int = 0
var peers: [ReplyThreadUserMessage] = []
}
var messageThreadStatsDifferences: [MessageId: MessageThreadStatsRecord] = [:]
func addMessageThreadStatsDifference(threadMessageId: MessageId, remove: Int, addedMessagePeer: PeerId?, addedMessageId: MessageId?, isOutgoing: Bool) {
if let value = messageThreadStatsDifferences[threadMessageId] {
var messageThreadStatsDifferences: [MessageThreadKey: MessageThreadStatsRecord] = [:]
func addMessageThreadStatsDifference(threadKey: MessageThreadKey, remove: Int, addedMessagePeer: PeerId?, addedMessageId: MessageId?, isOutgoing: Bool) {
if let value = messageThreadStatsDifferences[threadKey] {
value.removedCount += remove
if let addedMessagePeer = addedMessagePeer, let addedMessageId = addedMessageId {
value.peers.append(ReplyThreadUserMessage(id: addedMessagePeer, messageId: addedMessageId, isOutgoing: isOutgoing))
}
} else {
let value = MessageThreadStatsRecord()
messageThreadStatsDifferences[threadMessageId] = value
messageThreadStatsDifferences[threadKey] = value
value.removedCount = remove
if let addedMessagePeer = addedMessagePeer, let addedMessageId = addedMessageId {
value.peers.append(ReplyThreadUserMessage(id: addedMessagePeer, messageId: addedMessageId, isOutgoing: isOutgoing))
@ -3540,10 +3540,9 @@ func replayFinalState(
}
}
let messageThreadId = makeThreadIdMessageId(peerId: message.id.peerId, threadId: threadId)
if id.peerId.namespace == Namespaces.Peer.CloudChannel {
if !transaction.messageExists(id: id) {
addMessageThreadStatsDifference(threadMessageId: messageThreadId, remove: 0, addedMessagePeer: message.authorId, addedMessageId: id, isOutgoing: !message.flags.contains(.Incoming))
addMessageThreadStatsDifference(threadKey: MessageThreadKey(peerId: message.id.peerId, threadId: threadId), remove: 0, addedMessagePeer: message.authorId, addedMessageId: id, isOutgoing: !message.flags.contains(.Incoming))
}
}
@ -3736,7 +3735,7 @@ func replayFinalState(
deletedMessageIds.append(contentsOf: ids.map { .global($0) })
case let .DeleteMessages(ids):
_internal_deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids, manualAddMessageThreadStatsDifference: { id, add, remove in
addMessageThreadStatsDifference(threadMessageId: id, remove: remove, addedMessagePeer: nil, addedMessageId: nil, isOutgoing: false)
addMessageThreadStatsDifference(threadKey: id, remove: remove, addedMessagePeer: nil, addedMessageId: nil, isOutgoing: false)
})
deletedMessageIds.append(contentsOf: ids.map { .messageId($0) })
case let .UpdateMinAvailableMessage(id):
@ -4784,8 +4783,8 @@ func replayFinalState(
// }
// }
for (threadMessageId, difference) in messageThreadStatsDifferences {
updateMessageThreadStats(transaction: transaction, threadMessageId: threadMessageId, removedCount: difference.removedCount, addedMessagePeers: difference.peers)
for (threadKey, difference) in messageThreadStatsDifferences {
updateMessageThreadStats(transaction: transaction, threadKey: threadKey, removedCount: difference.removedCount, addedMessagePeers: difference.peers)
}
if !peerActivityTimestamps.isEmpty {

View file

@ -1088,7 +1088,7 @@ public final class AccountStateManager {
for attr in first.attributes {
if let attribute = attr as? ReplyMessageAttribute {
if let threadId = attribute.threadMessageId {
threadData = transaction.getMessageHistoryThreadInfo(peerId: first.id.peerId, threadId: makeMessageThreadId(threadId))?.data.get(MessageHistoryThreadData.self)
threadData = transaction.getMessageHistoryThreadInfo(peerId: first.id.peerId, threadId: Int64(threadId.id))?.data.get(MessageHistoryThreadData.self)
}
}
}
@ -1999,7 +1999,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
}
if let attribute = attribute as? ReplyMessageAttribute {
if let threadId = attribute.threadMessageId {
threadData = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: makeMessageThreadId(threadId))?.data.get(MessageHistoryThreadData.self)
threadData = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: Int64(threadId.id))?.data.get(MessageHistoryThreadData.self)
}
}
}

View file

@ -96,7 +96,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
var updatedTimestamp: Int32?
if let apiMessage = apiMessage {
switch apiMessage {
case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _):
updatedTimestamp = date
case .messageEmpty:
break
@ -287,9 +287,8 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
if let updatedMessage = updatedMessage, case let .Id(updatedId) = updatedMessage.id {
if message.id.namespace == Namespaces.Message.Local && updatedId.namespace == Namespaces.Message.Cloud && updatedId.peerId.namespace == Namespaces.Peer.CloudChannel {
if let threadId = updatedMessage.threadId {
let messageThreadId = makeThreadIdMessageId(peerId: updatedMessage.id.peerId, threadId: threadId)
if let authorId = updatedMessage.authorId {
updateMessageThreadStats(transaction: transaction, threadMessageId: messageThreadId, removedCount: 0, addedMessagePeers: [ReplyThreadUserMessage(id: authorId, messageId: updatedId, isOutgoing: true)])
updateMessageThreadStats(transaction: transaction, threadKey: MessageThreadKey(peerId: updatedMessage.id.peerId, threadId: threadId), removedCount: 0, addedMessagePeers: [ReplyThreadUserMessage(id: authorId, messageId: updatedId, isOutgoing: true)])
}
}
}

View file

@ -234,7 +234,7 @@ final class HistoryViewStateValidationContexts {
context.batchReferences[messageId] = batch
}
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, tag: view.tagMask, messageIds: messages)
disposable.set((validateReplyThreadMessagesBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, peerId: peerId, threadMessageId: Int32(clamping: threadId), tag: view.tagMask, messageIds: messages)
|> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
var completedMessageIds: [MessageId] = []
@ -512,7 +512,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
} else if tag == MessageTags.unseenReaction {
requestSignal = network.request(Api.functions.messages.getUnreadReactions(flags: 0, peer: inputPeer, topMsgId: nil, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1))
} else if let filter = messageFilterForTagMask(tag) {
requestSignal = network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
requestSignal = network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, savedPeerId: nil, topMsgId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
} else {
assertionFailure()
requestSignal = .complete()
@ -582,7 +582,7 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
var flags: Int32 = 0
flags |= (1 << 1)
requestSignal = network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: threadMessageId, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
requestSignal = network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, savedPeerId: nil, topMsgId: threadMessageId, filter: filter, minDate: 0, maxDate: 0, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
} else {
return .complete()
}
@ -621,7 +621,7 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
return .complete()
}
return validateReplyThreadBatch(postbox: postbox, network: network, transaction: transaction, accountPeerId: accountPeerId, peerId: peerId, threadId: makeMessageThreadId(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: threadMessageId)), signal: signal, previous: previous, messageNamespace: Namespaces.Message.Cloud)
return validateReplyThreadBatch(postbox: postbox, network: network, transaction: transaction, accountPeerId: accountPeerId, peerId: peerId, threadId: Int64(threadMessageId), signal: signal, previous: previous, messageNamespace: Namespaces.Message.Cloud)
}
|> switchToLatest
}

View file

@ -335,16 +335,29 @@ enum FetchMessageHistoryHoleThreadInput: CustomStringConvertible {
}
}
var requestThreadId: MessageId? {
func requestThreadId(accountPeerId: PeerId) -> Int64? {
switch self {
case let .direct(peerId, threadId):
if let threadId = threadId {
return makeThreadIdMessageId(peerId: peerId, threadId: threadId)
if let threadId = threadId, peerId != accountPeerId {
return threadId
} else {
return nil
}
case let .threadFromChannel(channelMessageId):
return channelMessageId
return Int64(channelMessageId.id)
}
}
func requestSubPeerId(accountPeerId: PeerId) -> PeerId? {
switch self {
case let .direct(peerId, threadId):
if let threadId = threadId, peerId == accountPeerId {
return PeerId(threadId)
} else {
return nil
}
case .threadFromChannel:
return nil
}
}
}
@ -360,10 +373,6 @@ struct FetchMessageHistoryHoleResult: Equatable {
func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryHoleSource, postbox: Postbox, peerInput: FetchMessageHistoryHoleThreadInput, namespace: MessageId.Namespace, direction: MessageHistoryViewRelativeHoleDirection, space: MessageHistoryHoleSpace, count rawCount: Int) -> Signal<FetchMessageHistoryHoleResult?, NoError> {
let count = min(100, rawCount)
if peerInput.requestThreadId != nil, case .everywhere = space, case .aroundId = direction {
assert(true)
}
return postbox.stateView()
|> mapToSignal { view -> Signal<AuthorizedAccountState, NoError> in
if let state = view.state as? AuthorizedAccountState {
@ -374,15 +383,15 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
}
|> take(1)
|> mapToSignal { _ -> Signal<FetchMessageHistoryHoleResult?, NoError> in
return postbox.transaction { transaction -> (Peer?, Int64) in
return postbox.transaction { transaction -> (Peer?, Int64, Peer?) in
switch peerInput {
case let .direct(peerId, _):
return (transaction.getPeer(peerId), 0)
return (transaction.getPeer(peerId), 0, peerInput.requestSubPeerId(accountPeerId: accountPeerId).flatMap(transaction.getPeer))
case let .threadFromChannel(channelMessageId):
return (transaction.getPeer(channelMessageId.peerId), 0)
return (transaction.getPeer(channelMessageId.peerId), 0, nil)
}
}
|> mapToSignal { (peer, hash) -> Signal<FetchMessageHistoryHoleResult?, NoError> in
|> mapToSignal { (peer, hash, subPeer) -> Signal<FetchMessageHistoryHoleResult?, NoError> in
guard let peer = peer else {
return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet(), actualPeerId: nil, actualThreadId: nil, ids: []))
}
@ -397,284 +406,345 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
let minMaxRange: ClosedRange<MessageId.Id>
switch space {
case .everywhere:
if let requestThreadId = peerInput.requestThreadId {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
case .everywhere:
if let requestThreadId = peerInput.requestThreadId(accountPeerId: accountPeerId) {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
minMaxRange = 1 ... (Int32.max - 1)
}
request = source.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: requestThreadId.id, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: hash))
} else {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id == 1 ? 0 : end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... Int32.max - 1
}
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
}
case let .tag(tag):
assert(tag.containsSingleElement)
if tag == .unseenPersonalMessage {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
minMaxRange = 1 ... Int32.max - 1
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 1)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.getUnreadMentions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .unseenReaction {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... Int32.max - 1
}
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 0)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.getUnreadReactions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .liveLocation {
let selectedLimit = count
switch direction {
case .aroundId, .range:
implicitelyFillHole = true
}
minMaxRange = 1 ... (Int32.max - 1)
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0))
} else if let filter = messageFilterForTagMask(tag) {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... (Int32.max - 1)
}
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId {
flags |= (1 << 1)
topMsgId = threadId.id
}
request = source.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
} else {
assertionFailure()
minMaxRange = 1 ... 1
request = .never()
}
request = source.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: Int32(clamping: requestThreadId), offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: hash))
} else if let subPeerId = peerInput.requestSubPeerId(accountPeerId: accountPeerId) {
guard let subPeer, subPeer.id == subPeerId, let inputSubPeer = apiInputPeer(subPeer) else {
Logger.shared.log("fetchMessageHistoryHole", "subPeer not available")
return .never()
}
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... (Int32.max - 1)
}
request = source.request(Api.functions.messages.getSavedHistory(peer: inputSubPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: hash))
} else {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id == 1 ? 0 : end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... Int32.max - 1
}
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
}
case let .tag(tag):
assert(tag.containsSingleElement)
if tag == .unseenPersonalMessage {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... Int32.max - 1
}
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId(accountPeerId: accountPeerId) {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
}
request = source.request(Api.functions.messages.getUnreadMentions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .unseenReaction {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... Int32.max - 1
}
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId(accountPeerId: accountPeerId) {
flags |= (1 << 0)
topMsgId = Int32(clamping: threadId)
}
request = source.request(Api.functions.messages.getUnreadReactions(flags: flags, peer: inputPeer, topMsgId: topMsgId, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
} else if tag == .liveLocation {
let selectedLimit = count
switch direction {
case .aroundId, .range:
implicitelyFillHole = true
}
minMaxRange = 1 ... (Int32.max - 1)
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0))
} else if let filter = messageFilterForTagMask(tag) {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
let rangeStartId = start.id
let rangeEndId = min(end.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
let rangeStartId = end.id
let rangeEndId = min(start.id, Int32.max - 1)
if rangeStartId <= rangeEndId {
minMaxRange = rangeStartId ... rangeEndId
} else {
minMaxRange = rangeStartId ... rangeStartId
assertionFailure()
}
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
minMaxRange = 1 ... (Int32.max - 1)
}
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = peerInput.requestThreadId(accountPeerId: accountPeerId) {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
}
var savedPeerId: Api.InputPeer?
if let subPeerId = peerInput.requestSubPeerId(accountPeerId: accountPeerId), let subPeer = subPeer, subPeer.id == subPeerId {
if let inputPeer = apiInputPeer(subPeer) {
flags |= 1 << 2
savedPeerId = inputPeer
}
}
request = source.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, savedPeerId: savedPeerId, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
} else {
assertionFailure()
minMaxRange = 1 ... 1
request = .never()
}
}
return request
@ -784,7 +854,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
}
print("fetchMessageHistoryHole for \(peerInput) space \(space) done")
if peerInput.requestThreadId != nil, case .everywhere = space, case .aroundId = direction {
if peerInput.requestThreadId(accountPeerId: accountPeerId) != nil, case .everywhere = space, case .aroundId = direction {
assert(true)
}
@ -797,7 +867,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
case let .aroundId(aroundId):
filledRange = min(aroundId.id, messageRange.lowerBound) ... max(aroundId.id, messageRange.upperBound)
strictFilledIndices = IndexSet(integersIn: Int(min(aroundId.id, messageRange.lowerBound)) ... Int(max(aroundId.id, messageRange.upperBound)))
if peerInput.requestThreadId != nil {
if peerInput.requestThreadId(accountPeerId: accountPeerId) != nil {
if ids.count <= count / 2 - 1 {
filledRange = minMaxRange
}
@ -973,7 +1043,7 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId
offset = single((holeIndex.timestamp, min(holeIndex.id.id, Int32.max - 1) + 1, Api.InputPeer.inputPeerEmpty), NoError.self)
return offset
|> mapToSignal { (timestamp, id, peer) -> Signal<Void, NoError> in
let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, topMsgId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0))
let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, savedPeerId: nil, topMsgId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0))
|> retryRequest
|> mapToSignal { result -> Signal<Void, NoError> in
let messages: [Api.Message]

View file

@ -177,11 +177,11 @@ private func requestActivity(postbox: Postbox, network: Network, accountPeerId:
if let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0
let topMessageId = threadId.flatMap { makeThreadIdMessageId(peerId: peerId, threadId: $0) }
let topMessageId = threadId.flatMap { Int32(clamping: $0) }
if topMessageId != nil {
flags |= 1 << 0
}
return network.request(Api.functions.messages.setTyping(flags: flags, peer: inputPeer, topMsgId: topMessageId?.id, action: actionFromActivity(activity)))
return network.request(Api.functions.messages.setTyping(flags: flags, peer: inputPeer, topMsgId: topMessageId, action: actionFromActivity(activity)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}

View file

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 169
return 170
}
public func parseMessage(_ data: Data!) -> Any! {

View file

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups)
}
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
let generatedPeerId = Api.Peer.peerUser(userId: userId)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {

View file

@ -104,7 +104,7 @@ extension Api.MessageMedia {
extension Api.Message {
var rawId: Int32 {
switch self {
case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return id
case let .messageEmpty(_, id, _):
return id
@ -115,7 +115,7 @@ extension Api.Message {
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
switch self {
case let .message(_, id, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, id, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
let peerId: PeerId = messagePeerId.peerId
return MessageId(peerId: peerId, namespace: namespace, id: id)
case let .messageEmpty(_, id, peerId):
@ -132,7 +132,7 @@ extension Api.Message {
var peerId: PeerId? {
switch self {
case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
let peerId: PeerId = messagePeerId.peerId
return peerId
case let .messageEmpty(_, _, peerId):
@ -145,7 +145,7 @@ extension Api.Message {
var timestamp: Int32? {
switch self {
case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _):
return date
case let .messageService(_, _, _, _, _, date, _, _):
return date
@ -156,7 +156,7 @@ extension Api.Message {
var preCachedResources: [(MediaResource, Data)]? {
switch self {
case let .message(_, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _):
return media?.preCachedResources
default:
return nil
@ -165,7 +165,7 @@ extension Api.Message {
var preCachedStories: [StoryId: Api.StoryItem]? {
switch self {
case let .message(_, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _):
return media?.preCachedStories
default:
return nil

View file

@ -138,12 +138,3 @@ public class ReplyStoryAttribute: MessageAttribute {
encoder.encode(self.storyId, forKey: "i")
}
}
public extension Message {
var effectiveReplyThreadMessageId: MessageId? {
if let threadId = self.threadId {
return makeThreadIdMessageId(peerId: self.id.peerId, threadId: threadId)
}
return nil
}
}

View file

@ -190,6 +190,13 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
}
}
return false
},
automaticThreadIndexInfo: { peerId, _ in
if peerId.namespace == Namespaces.Peer.CloudUser {
return StoredMessageHistoryThreadInfo(data: CodableEntry(data: Data()), summary: StoredMessageHistoryThreadInfo.Summary(totalUnreadCount: 0, mutedUntil: nil))
} else {
return nil
}
}
)
}()

View file

@ -22,7 +22,7 @@ func addMessageMediaResourceIdsToRemove(message: Message, resourceIds: inout [Me
}
}
public func _internal_deleteMessages(transaction: Transaction, mediaBox: MediaBox, ids: [MessageId], deleteMedia: Bool = true, manualAddMessageThreadStatsDifference: ((MessageId, Int, Int) -> Void)? = nil) {
public func _internal_deleteMessages(transaction: Transaction, mediaBox: MediaBox, ids: [MessageId], deleteMedia: Bool = true, manualAddMessageThreadStatsDifference: ((MessageThreadKey, Int, Int) -> Void)? = nil) {
var resourceIds: [MediaResourceId] = []
if deleteMedia {
for id in ids {
@ -40,12 +40,12 @@ public func _internal_deleteMessages(transaction: Transaction, mediaBox: MediaBo
if id.peerId.namespace == Namespaces.Peer.CloudChannel && id.namespace == Namespaces.Message.Cloud {
if let message = transaction.getMessage(id) {
if let threadId = message.threadId {
let messageThreadId = makeThreadIdMessageId(peerId: message.id.peerId, threadId: threadId)
let messageThreadKey = MessageThreadKey(peerId: message.id.peerId, threadId: threadId)
if id.peerId.namespace == Namespaces.Peer.CloudChannel {
if let manualAddMessageThreadStatsDifference = manualAddMessageThreadStatsDifference {
manualAddMessageThreadStatsDifference(messageThreadId, 0, 1)
manualAddMessageThreadStatsDifference(messageThreadKey, 0, 1)
} else {
updateMessageThreadStats(transaction: transaction, threadMessageId: messageThreadId, removedCount: 1, addedMessagePeers: [])
updateMessageThreadStats(transaction: transaction, threadKey: messageThreadKey, removedCount: 1, addedMessagePeers: [])
}
}
}

View file

@ -17,7 +17,8 @@ private struct DiscussionMessage {
private class ReplyThreadHistoryContextImpl {
private let queue: Queue
private let account: Account
private let messageId: MessageId
private let peerId: PeerId
private let threadId: Int64
private var currentHole: (MessageHistoryHolesViewEntry, Disposable)?
@ -68,7 +69,10 @@ private class ReplyThreadHistoryContextImpl {
init(queue: Queue, account: Account, data: ChatReplyThreadMessage) {
self.queue = queue
self.account = account
self.messageId = data.messageId
self.peerId = data.peerId
self.threadId = data.threadId
let referencedMessageId = MessageId(peerId: data.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: data.threadId))
self.maxReadOutgoingMessageIdValue = data.maxReadOutgoingMessageId
self.maxReadOutgoingMessageId.set(.single(self.maxReadOutgoingMessageIdValue))
@ -79,7 +83,7 @@ private class ReplyThreadHistoryContextImpl {
self.unreadCount.set(.single(self.unreadCountValue))
self.initialStateDisposable = (account.postbox.transaction { transaction -> State in
var indices = transaction.getThreadIndexHoles(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), namespace: Namespaces.Message.Cloud)
var indices = transaction.getThreadIndexHoles(peerId: data.peerId, threadId: data.threadId, namespace: Namespaces.Message.Cloud)
indices.subtract(data.initialFilledHoles)
/*let isParticipant = transaction.getPeerChatListIndex(data.messageId.peerId) != nil
@ -96,7 +100,7 @@ private class ReplyThreadHistoryContextImpl {
indices.removeAll()
}
return State(messageId: data.messageId, holeIndices: [Namespaces.Message.Cloud: indices], maxReadIncomingMessageId: data.maxReadIncomingMessageId, maxReadOutgoingMessageId: data.maxReadOutgoingMessageId)
return State(messageId: referencedMessageId, holeIndices: [Namespaces.Message.Cloud: indices], maxReadIncomingMessageId: data.maxReadIncomingMessageId, maxReadOutgoingMessageId: data.maxReadOutgoingMessageId)
}
|> deliverOn(self.queue)).start(next: { [weak self] state in
guard let strongSelf = self else {
@ -106,7 +110,7 @@ private class ReplyThreadHistoryContextImpl {
strongSelf.state.set(.single(state))
})
let threadId = makeMessageThreadId(messageId)
let threadId = self.threadId
self.holesDisposable = (account.postbox.messageHistoryHolesView()
|> map { view -> MessageHistoryHolesViewEntry? in
@ -133,15 +137,15 @@ private class ReplyThreadHistoryContextImpl {
guard let strongSelf = self else {
return
}
if let value = outgoing[data.messageId] {
strongSelf.maxReadOutgoingMessageIdValue = MessageId(peerId: data.messageId.peerId, namespace: Namespaces.Message.Cloud, id: value)
if let value = outgoing[referencedMessageId] {
strongSelf.maxReadOutgoingMessageIdValue = MessageId(peerId: data.peerId, namespace: Namespaces.Message.Cloud, id: value)
}
})
let accountPeerId = account.peerId
let updateInitialState: Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> = account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(data.messageId.peerId)
return transaction.getPeer(data.peerId)
}
|> castError(FetchChannelReplyThreadMessageError.self)
|> mapToSignal { peer -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
@ -151,8 +155,8 @@ private class ReplyThreadHistoryContextImpl {
guard let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
}
return account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: data.messageId.id))
return account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: Int32(clamping: data.threadId)))
|> mapError { _ -> FetchChannelReplyThreadMessageError in
return .generic
}
@ -308,9 +312,10 @@ private class ReplyThreadHistoryContextImpl {
}
func applyMaxReadIndex(messageIndex: MessageIndex) {
let messageId = self.messageId
let peerId = self.peerId
let threadId = self.threadId
if messageIndex.id.namespace != messageId.namespace {
if messageIndex.id.namespace != Namespaces.Message.Cloud {
return
}
@ -326,16 +331,16 @@ private class ReplyThreadHistoryContextImpl {
let account = self.account
let _ = (self.account.postbox.transaction { transaction -> (Api.InputPeer?, MessageId?, Int?) in
if var data = transaction.getMessageHistoryThreadInfo(peerId: messageId.peerId, threadId: Int64(messageId.id))?.data.get(MessageHistoryThreadData.self) {
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
if messageIndex.id.id >= data.maxIncomingReadId {
if let count = transaction.getThreadMessageCount(peerId: messageId.peerId, threadId: Int64(messageId.id), namespace: messageId.namespace, fromIdExclusive: data.maxIncomingReadId, toIndex: messageIndex) {
if let count = transaction.getThreadMessageCount(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, fromIdExclusive: data.maxIncomingReadId, toIndex: messageIndex) {
data.incomingUnreadCount = max(0, data.incomingUnreadCount - Int32(count))
data.maxIncomingReadId = messageIndex.id.id
}
if let topMessageIndex = transaction.getMessageHistoryThreadTopMessage(peerId: messageId.peerId, threadId: Int64(messageId.id), namespaces: Set([Namespaces.Message.Cloud])) {
if let topMessageIndex = transaction.getMessageHistoryThreadTopMessage(peerId: peerId, threadId: threadId, namespaces: Set([Namespaces.Message.Cloud])) {
if messageIndex.id.id >= topMessageIndex.id.id {
let containingHole = transaction.getThreadIndexHole(peerId: messageId.peerId, threadId: Int64(messageId.id), namespace: topMessageIndex.id.namespace, containing: topMessageIndex.id.id)
let containingHole = transaction.getThreadIndexHole(peerId: peerId, threadId: threadId, namespace: topMessageIndex.id.namespace, containing: topMessageIndex.id.id)
if let _ = containingHole[.everywhere] {
} else {
data.incomingUnreadCount = 0
@ -346,12 +351,13 @@ private class ReplyThreadHistoryContextImpl {
data.maxKnownMessageId = max(data.maxKnownMessageId, messageIndex.id.id)
if let entry = StoredMessageHistoryThreadInfo(data) {
transaction.setMessageHistoryThreadInfo(peerId: messageId.peerId, threadId: Int64(messageId.id), info: entry)
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
}
}
if let message = transaction.getMessage(messageId) {
let referencedMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))
if let message = transaction.getMessage(referencedMessageId) {
for attribute in message.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute {
if let sourceMessage = transaction.getMessage(attribute.messageId) {
@ -388,8 +394,8 @@ private class ReplyThreadHistoryContextImpl {
}
let inputPeer = transaction.getPeer(messageIndex.id.peerId).flatMap(apiInputPeer)
let readCount = transaction.getThreadMessageCount(peerId: messageId.peerId, threadId: makeMessageThreadId(messageId), namespace: messageId.namespace, fromIdExclusive: fromIdExclusive, toIndex: toIndex)
let topMessageId = transaction.getMessagesWithThreadId(peerId: messageId.peerId, namespace: messageId.namespace, threadId: makeMessageThreadId(messageId), from: MessageIndex.upperBound(peerId: messageId.peerId, namespace: messageId.namespace), includeFrom: false, to: MessageIndex.lowerBound(peerId: messageId.peerId, namespace: messageId.namespace), limit: 1).first?.id
let readCount = transaction.getThreadMessageCount(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, fromIdExclusive: fromIdExclusive, toIndex: toIndex)
let topMessageId = transaction.getMessagesWithThreadId(peerId: peerId, namespace: Namespaces.Message.Cloud, threadId: threadId, from: MessageIndex.upperBound(peerId: peerId, namespace: Namespaces.Message.Cloud), includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: Namespaces.Message.Cloud), limit: 1).first?.id
return (inputPeer, topMessageId, readCount)
}
@ -434,17 +440,17 @@ private class ReplyThreadHistoryContextImpl {
}
}
var signal = strongSelf.account.network.request(Api.functions.messages.readDiscussion(peer: inputPeer, msgId: messageId.id, readMaxId: messageIndex.id.id))
var signal = strongSelf.account.network.request(Api.functions.messages.readDiscussion(peer: inputPeer, msgId: Int32(clamping: threadId), readMaxId: messageIndex.id.id))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> ignoreValues
if revalidate {
let validateSignal = strongSelf.account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: messageId.id))
let validateSignal = strongSelf.account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: Int32(clamping: threadId)))
|> map { result -> (MessageId?, Int) in
switch result {
case let .discussionMessage(_, _, _, readInboxMaxId, _, unreadCount, _, _):
return (readInboxMaxId.flatMap({ MessageId(peerId: messageId.peerId, namespace: messageId.namespace, id: $0) }), Int(unreadCount))
return (readInboxMaxId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }), Int(unreadCount))
}
}
|> `catch` { _ -> Signal<(MessageId?, Int)?, NoError> in
@ -494,7 +500,7 @@ public class ReplyThreadHistoryContext {
self.impl.with { impl in
let stateDisposable = impl.state.get().start(next: { state in
subscriber.putNext(MessageHistoryViewExternalInput(
content: .thread(peerId: state.messageId.peerId, id: makeMessageThreadId(state.messageId), holes: state.holeIndices),
content: .thread(peerId: state.messageId.peerId, id: Int64(state.messageId.id), holes: state.holeIndices),
maxReadIncomingMessageId: state.maxReadIncomingMessageId,
maxReadOutgoingMessageId: state.maxReadOutgoingMessageId
))
@ -554,7 +560,7 @@ public struct ChatReplyThreadMessage: Equatable {
case lowerBoundMessage(MessageIndex)
}
public var messageId: MessageId
public var peerId: PeerId
public var threadId: Int64
public var channelMessageId: MessageId?
public var isChannelPost: Bool
@ -567,8 +573,16 @@ public struct ChatReplyThreadMessage: Equatable {
public var initialAnchor: Anchor
public var isNotAvailable: Bool
public init(messageId: MessageId, threadId: Int64, channelMessageId: MessageId?, isChannelPost: Bool, isForumPost: Bool, maxMessage: MessageId?, maxReadIncomingMessageId: MessageId?, maxReadOutgoingMessageId: MessageId?, unreadCount: Int, initialFilledHoles: IndexSet, initialAnchor: Anchor, isNotAvailable: Bool) {
self.messageId = messageId
public var effectiveMessageId: MessageId? {
if self.peerId.namespace == Namespaces.Peer.CloudChannel {
return MessageId(peerId: self.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: self.threadId))
} else {
return nil
}
}
public init(peerId: PeerId, threadId: Int64, channelMessageId: MessageId?, isChannelPost: Bool, isForumPost: Bool, maxMessage: MessageId?, maxReadIncomingMessageId: MessageId?, maxReadOutgoingMessageId: MessageId?, unreadCount: Int, initialFilledHoles: IndexSet, initialAnchor: Anchor, isNotAvailable: Bool) {
self.peerId = peerId
self.threadId = threadId
self.channelMessageId = channelMessageId
self.isChannelPost = isChannelPost
@ -584,7 +598,7 @@ public struct ChatReplyThreadMessage: Equatable {
public var normalized: ChatReplyThreadMessage {
if self.isForumPost {
return ChatReplyThreadMessage(messageId: self.messageId, threadId: self.threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)
return ChatReplyThreadMessage(peerId: self.peerId, threadId: self.threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)
} else {
return self
}
@ -760,32 +774,6 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|> mapToSignal { threadData -> Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, Anchor, MessageId?), FetchChannelReplyThreadMessageError> in
if let _ = threadData, !"".isEmpty {
return .fail(.generic)
/*return account.postbox.transaction { transaction -> (FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, Anchor, MessageId?) in
var threadInput: FetchMessageHistoryHoleThreadInput = .threadFromChannel(channelMessageId: messageId)
var threadMessageId: MessageId?
transaction.scanMessageAttributes(peerId: messageId.peerId, namespace: Namespaces.Message.Cloud, limit: 1000, { id, attributes in
for attribute in attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute {
if attribute.messageId == messageId {
threadMessageId = id
threadInput = .direct(peerId: id.peerId, threadId: makeMessageThreadId(id))
return false
}
}
}
return true
})
let anchor: Anchor
if let atMessageId = atMessageId {
anchor = .message(atMessageId)
} else if let maxReadIncomingMessageId = replyInfo.maxReadIncomingMessageId {
anchor = .message(maxReadIncomingMessageId)
} else {
anchor = .lowerBound
}
return (threadInput, replyInfo.commentsPeerId, threadMessageId, anchor, replyInfo.maxMessageId)
}
|> castError(FetchChannelReplyThreadMessageError.self)*/
} else {
return discussionMessage.get()
|> take(1)
@ -805,7 +793,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
} else {
anchor = .lowerBound
}
return .single((.direct(peerId: commentsPeerId, threadId: makeMessageThreadId(topMessageId)), commentsPeerId, discussionMessage.messageId, anchor, discussionMessage.maxMessage))
return .single((.direct(peerId: commentsPeerId, threadId: Int64(topMessageId.id)), commentsPeerId, discussionMessage.messageId, anchor, discussionMessage.maxMessage))
}
}
}
@ -820,7 +808,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
}
return account.postbox.transaction { transaction -> Signal<(FetchMessageHistoryHoleResult?, ChatReplyThreadMessage.Anchor), FetchChannelReplyThreadMessageError> in
if let threadMessageId = threadMessageId {
var holes = transaction.getThreadIndexHoles(peerId: threadMessageId.peerId, threadId: makeMessageThreadId(threadMessageId), namespace: Namespaces.Message.Cloud)
var holes = transaction.getThreadIndexHoles(peerId: threadMessageId.peerId, threadId: Int64(threadMessageId.id), namespace: Namespaces.Message.Cloud)
holes.remove(integersIn: Int(maxMessageId.id + 1) ..< Int(Int32.max))
let isParticipant = transaction.getPeerChatListIndex(commentsPeerId) != nil
@ -843,7 +831,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
input: .external(MessageHistoryViewExternalInput(
content: .thread(
peerId: commentsPeerId,
id: makeMessageThreadId(threadMessageId),
id: Int64(threadMessageId.id),
holes: [
Namespaces.Message.Cloud: holes
]
@ -932,12 +920,12 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
return account.postbox.transaction { transaction -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> in
if let initialFilledHoles = initialFilledHoles {
for range in initialFilledHoles.strictRemovedIndices.rangeView {
transaction.removeHole(peerId: discussionMessage.messageId.peerId, threadId: makeMessageThreadId(discussionMessage.messageId), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
transaction.removeHole(peerId: discussionMessage.messageId.peerId, threadId: Int64(discussionMessage.messageId.id), namespace: Namespaces.Message.Cloud, space: .everywhere, range: Int32(range.lowerBound) ... Int32(range.upperBound))
}
}
return .single(ChatReplyThreadMessage(
messageId: discussionMessage.messageId,
peerId: discussionMessage.messageId.peerId,
threadId: Int64(discussionMessage.messageId.id),
channelMessageId: discussionMessage.channelMessageId,
isChannelPost: discussionMessage.isChannelPost,

View file

@ -8,7 +8,7 @@ import MtProtoKit
public enum SearchMessagesLocation: Equatable {
case general(tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case group(groupId: PeerGroupId, tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, topMsgId: MessageId?, minDate: Int32?, maxDate: Int32?)
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, threadId: Int64?, minDate: Int32?, maxDate: Int32?)
case sentMedia(tags: MessageTags?)
}
@ -139,7 +139,7 @@ private func mergedState(transaction: Transaction, seedConfiguration: SeedConfig
for attribute in renderedMessage.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
if let threadMessageId = attribute.threadMessageId {
let threadId = makeMessageThreadId(threadMessageId)
let threadId = Int64(threadMessageId.id)
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
threadInfo[renderedMessage.id] = data
break
@ -224,7 +224,7 @@ private func mergedResult(_ state: SearchMessagesState) -> SearchMessagesResult
func _internal_searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
let remoteSearchResult: Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError>
switch location {
case let .peer(peerId, fromId, tags, topMsgId, minDate, maxDate):
case let .peer(peerId, fromId, tags, threadId, minDate, maxDate):
if peerId.namespace == Namespaces.Peer.SecretChat {
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
var readStates: [PeerId: CombinedPeerReadState] = [:]
@ -238,7 +238,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
if let threadMessageId = attribute.threadMessageId {
let threadId = makeMessageThreadId(threadMessageId)
let threadId = Int64(threadMessageId.id)
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
threadInfo[message.id] = data
break
@ -253,7 +253,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
}
let filter: Api.MessagesFilter = tags.flatMap { messageFilterForTagMask($0) } ?? .inputMessagesFilterEmpty
remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?)? in
remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?, subPeer: Peer?)? in
guard let peer = transaction.getPeer(peerId) else {
return nil
}
@ -261,10 +261,12 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
if let _ = peer as? TelegramChannel, let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
additionalPeer = transaction.getPeer(migrationReference.maxMessageId.peerId)
}
if let fromId = fromId {
return (peer: peer, additionalPeer: additionalPeer, from: transaction.getPeer(fromId))
var subPeer: Peer?
if peerId == account.peerId, let threadId = threadId {
subPeer = transaction.getPeer(PeerId(threadId))
}
return (peer: peer, additionalPeer: additionalPeer, from: nil)
return (peer: peer, additionalPeer: additionalPeer, from: fromId.flatMap(transaction.getPeer), subPeer)
}
|> mapToSignal { values -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in
guard let values = values else {
@ -282,8 +284,18 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
flags |= (1 << 0)
}
}
if let _ = topMsgId {
var inputSavedPeer: Api.InputPeer? = nil
if let subPeer = values.subPeer {
if let inputPeer = apiInputPeer(subPeer) {
inputSavedPeer = inputPeer
flags |= (1 << 2)
}
}
var topMsgId: Int32?
if peerId == account.peerId {
} else if let threadId = threadId {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
}
let peerMessages: Signal<Api.messages.Messages?, NoError>
if let completed = state?.main.completed, completed {
@ -294,7 +306,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
if peer.id.namespace == Namespaces.Peer.CloudChannel && query.isEmpty && fromId == nil && tags == nil && minDate == nil && maxDate == nil {
signal = account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: lowerBound?.id.id ?? 0, offsetDate: 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
} else {
signal = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputPeer, topMsgId: topMsgId?.id, filter: filter, minDate: minDate ?? 0, maxDate: maxDate ?? (Int32.max - 1), offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
signal = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputPeer, savedPeerId: inputSavedPeer, topMsgId: topMsgId, filter: filter, minDate: minDate ?? 0, maxDate: maxDate ?? (Int32.max - 1), offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
}
peerMessages = signal
|> map(Optional.init)
@ -310,7 +322,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
additionalPeerMessages = .single(nil)
} else if mainCompleted || !hasAdditional {
let lowerBound = state?.additional?.messages.last.flatMap({ $0.index })
additionalPeerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputPeer, topMsgId: topMsgId?.id, filter: filter, minDate: minDate ?? 0, maxDate: maxDate ?? (Int32.max - 1), offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
additionalPeerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputPeer, savedPeerId: inputSavedPeer, topMsgId: topMsgId, filter: filter, minDate: minDate ?? 0, maxDate: maxDate ?? (Int32.max - 1), offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in
return .single(nil)
@ -397,7 +409,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
if let threadMessageId = attribute.threadMessageId {
let threadId = makeMessageThreadId(threadMessageId)
let threadId = Int64(threadMessageId.id)
if let data = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
threadInfo[message.id] = data
break
@ -603,10 +615,11 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
return .single(transaction.findClosestMessageIdByTimestamp(peerId: peerId, timestamp: timestamp))
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
if let threadId = threadId {
let primaryIndex = account.network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
if peerId.namespace == Namespaces.Peer.CloudChannel {
let primaryIndex = account.network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: Int32(clamping: threadId), offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _):
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
@ -615,21 +628,55 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
messages = apiMessages
case .messagesNotModified:
messages = []
}
for message in messages {
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: peer.isForum) {
return message.index
}
for message in messages {
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: peer.isForum) {
return message.index
}
}
return nil
}
return nil
}
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
return .single(nil)
}
return primaryIndex
|> map { primaryIndex -> MessageId? in
return primaryIndex?.id
}
} else if peerId == account.peerId {
guard let subPeer = transaction.getPeer(PeerId(threadId)), let inputSubPeer = apiInputPeer(subPeer) else {
return .single(nil)
}
let primaryIndex = account.network.request(Api.functions.messages.getSavedHistory(peer: inputSubPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _):
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
messages = apiMessages
case .messagesNotModified:
messages = []
}
for message in messages {
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: peer.isForum) {
return message.index
}
}
return nil
}
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
return .single(nil)
}
return primaryIndex
|> map { primaryIndex -> MessageId? in
return primaryIndex?.id
}
} else {
return .single(nil)
}
return primaryIndex
|> map { primaryIndex -> MessageId? in
return primaryIndex?.id
}
} else {
var secondaryIndex: Signal<MessageIndex?, NoError> = .single(nil)
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference, let secondaryPeer = transaction.getPeer(migrationReference.maxMessageId.peerId), let inputSecondaryPeer = apiInputPeer(secondaryPeer) {

View file

@ -105,14 +105,15 @@ public final class SparseMessageList {
self.sparseItemsDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<SparseItems, NoError> in
|> mapToSignal { inputPeer -> Signal<SparseItems, NoError> in
guard let inputPeer = inputPeer else {
return .single(SparseItems(items: []))
}
guard let messageFilter = messageFilterForTagMask(messageTag) else {
return .single(SparseItems(items: []))
}
return account.network.request(Api.functions.messages.getSearchResultsPositions(peer: inputPeer, filter: messageFilter, offsetId: 0, limit: 1000))
//TODO:api
return account.network.request(Api.functions.messages.getSearchResultsPositions(flags: 0, peer: inputPeer, savedPeerId: nil, filter: messageFilter, offsetId: 0, limit: 1000))
|> map { result -> SparseItems in
switch result {
case let .searchResultsPositions(totalCount, positions):
@ -817,7 +818,8 @@ public final class SparseMessageCalendar {
guard let messageFilter = messageFilterForTagMask(messageTag) else {
return .single(LoadResult(messagesByDay: [:], nextOffset: nil, minMessageId: nil, minTimestamp: nil))
}
return self.account.network.request(Api.functions.messages.getSearchResultsCalendar(peer: inputPeer, filter: messageFilter, offsetId: nextRequestOffset, offsetDate: 0))
//TODO:api
return self.account.network.request(Api.functions.messages.getSearchResultsCalendar(flags: 0, peer: inputPeer, savedPeerId: nil, filter: messageFilter, offsetId: nextRequestOffset, offsetDate: 0))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.SearchResultsCalendar?, NoError> in
return .single(nil)

View file

@ -415,10 +415,16 @@ public extension TelegramEngine {
public func refreshMessageTagStats(peerId: EnginePeer.Id, threadId: Int64?, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
let account = self.account
return self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
return self.account.postbox.transaction { transaction -> (Api.InputPeer?, Api.InputPeer?) in
var inputSavedPeer: Api.InputPeer?
if let threadId = threadId {
if peerId == account.peerId {
inputSavedPeer = transaction.getPeer(PeerId(threadId)).flatMap(apiInputPeer)
}
}
return (transaction.getPeer(peerId).flatMap(apiInputPeer), inputSavedPeer)
}
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
|> mapToSignal { inputPeer, inputSavedPeer -> Signal<Never, NoError> in
guard let inputPeer = inputPeer else {
return .complete()
}
@ -432,11 +438,17 @@ public extension TelegramEngine {
var flags: Int32 = 0
var topMsgId: Int32?
if let threadId = threadId {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
if peerId == account.peerId {
if inputSavedPeer != nil {
flags |= (1 << 2)
}
} else {
flags |= (1 << 1)
topMsgId = Int32(clamping: threadId)
}
}
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, savedPeerId: inputSavedPeer, 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, _, _):

View file

@ -68,7 +68,7 @@ func _internal_requestPeerPhotos(accountPeerId: PeerId, postbox: Postbox, networ
}
}
} else if let peer = peer, let inputPeer = apiInputPeer(peer) {
return network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, topMsgId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0))
return network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, savedPeerId: nil, topMsgId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in
return .single(nil)

View file

@ -34,12 +34,12 @@ struct ReplyThreadUserMessage {
var isOutgoing: Bool
}
func updateMessageThreadStats(transaction: Transaction, threadMessageId: MessageId, removedCount: Int, addedMessagePeers: [ReplyThreadUserMessage]) {
updateMessageThreadStatsInternal(transaction: transaction, threadMessageId: threadMessageId, removedCount: removedCount, addedMessagePeers: addedMessagePeers, allowChannel: false)
func updateMessageThreadStats(transaction: Transaction, threadKey: MessageThreadKey, removedCount: Int, addedMessagePeers: [ReplyThreadUserMessage]) {
updateMessageThreadStatsInternal(transaction: transaction, threadKey: threadKey, removedCount: removedCount, addedMessagePeers: addedMessagePeers, allowChannel: false)
}
private func updateMessageThreadStatsInternal(transaction: Transaction, threadMessageId: MessageId, removedCount: Int, addedMessagePeers: [ReplyThreadUserMessage], allowChannel: Bool) {
guard let channel = transaction.getPeer(threadMessageId.peerId) as? TelegramChannel else {
private func updateMessageThreadStatsInternal(transaction: Transaction, threadKey: MessageThreadKey, removedCount: Int, addedMessagePeers: [ReplyThreadUserMessage], allowChannel: Bool) {
guard let channel = transaction.getPeer(threadKey.peerId) as? TelegramChannel else {
return
}
var isGroup = true
@ -75,7 +75,7 @@ private func updateMessageThreadStatsInternal(transaction: Transaction, threadMe
return current
}
transaction.updateMessage(threadMessageId, update: { currentMessage in
transaction.updateMessage(MessageId(peerId: threadKey.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadKey.threadId)), update: { currentMessage in
var attributes = currentMessage.attributes
loop: for j in 0 ..< attributes.count {
if let attribute = attributes[j] as? ReplyThreadMessageAttribute {
@ -117,6 +117,6 @@ private func updateMessageThreadStatsInternal(transaction: Transaction, threadMe
})
if let channelThreadMessageId = channelThreadMessageId {
updateMessageThreadStatsInternal(transaction: transaction, threadMessageId: channelThreadMessageId, removedCount: removedCount, addedMessagePeers: addedMessagePeers, allowChannel: true)
updateMessageThreadStatsInternal(transaction: transaction, threadKey: MessageThreadKey(peerId: channelThreadMessageId.peerId, threadId: Int64(channelThreadMessageId.id)), removedCount: removedCount, addedMessagePeers: addedMessagePeers, allowChannel: true)
}
}

View file

@ -56,7 +56,7 @@ private func titleAndColorForAction(_ action: SubscriberAction, theme: Presentat
}
private func actionForPeer(context: AccountContext, peer: Peer, interfaceState: ChatPresentationInterfaceState, isJoining: Bool, isMuted: Bool) -> SubscriberAction? {
if case let .replyThread(message) = interfaceState.chatLocation, message.messageId.peerId == context.account.peerId {
if case let .replyThread(message) = interfaceState.chatLocation, message.peerId == context.account.peerId {
if let peer = interfaceState.savedMessagesTopicPeer {
if case let .channel(channel) = peer {
if case .broadcast = channel.info {

View file

@ -196,7 +196,7 @@ public final class ChatHistorySearchContainerNode: SearchDisplayControllerConten
if let strongSelf = self {
let signal: Signal<([ChatHistorySearchEntry], [MessageId: Message])?, NoError>
if let query = query, !query.isEmpty {
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: threadId.flatMap { makeThreadIdMessageId(peerId: peerId, threadId: $0) }, minDate: nil, maxDate: nil), query: query, state: nil)
let foundRemoteMessages: Signal<[Message], NoError> = context.engine.messages.searchMessages(location: .peer(peerId: peerId, fromId: nil, tags: tagMask, threadId: threadId, minDate: nil, maxDate: nil), query: query, state: nil)
|> map { $0.0.messages }
|> delay(0.2, queue: Queue.concurrentDefaultQueue())

View file

@ -313,7 +313,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return false
}
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.messageId.peerId != item.content.firstMessage.id.peerId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.peerId != item.content.firstMessage.id.peerId {
return false
}
@ -826,8 +826,8 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
hasAvatar = true
}
case let .replyThread(replyThreadMessage):
if replyThreadMessage.messageId.peerId != item.context.account.peerId {
if replyThreadMessage.messageId.peerId.isGroupOrChannel && item.message.author != nil {
if replyThreadMessage.peerId != item.context.account.peerId {
if replyThreadMessage.peerId.isGroupOrChannel && item.message.author != nil {
var isBroadcastChannel = false
if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
isBroadcastChannel = true
@ -1102,7 +1102,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
if let replyAttribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == replyAttribute.messageId.id {
} else {
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
}

View file

@ -1215,7 +1215,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
}
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.messageId.peerId != item.content.firstMessage.id.peerId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.peerId != item.content.firstMessage.id.peerId {
return false
}
@ -1664,7 +1664,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
inlineBotNameString = attribute.title
}
} else if let attribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == attribute.messageId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == attribute.messageId.id {
} else {
replyMessage = firstMessage.associatedMessages[attribute.messageId]
}
@ -4185,7 +4185,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
if let item = self.item {
for attribute in item.message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
if let threadId = item.message.threadId, makeThreadIdMessageId(peerId: item.message.id.peerId, threadId: threadId) == attribute.messageId, let quotedReply = item.message.attributes.first(where: { $0 is QuotedReplyMessageAttribute }) as? QuotedReplyMessageAttribute {
if let threadId = item.message.threadId, Int32(clamping: threadId) == attribute.messageId.id, let quotedReply = item.message.attributes.first(where: { $0 is QuotedReplyMessageAttribute }) as? QuotedReplyMessageAttribute {
return .action(InternalBubbleTapAction.Action({ [weak self, weak replyInfoNode] in
guard let self, let item = self.item, let replyInfoNode else {
return

View file

@ -221,7 +221,7 @@ public class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureReco
return false
}
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.messageId.peerId != item.content.firstMessage.id.peerId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.peerId != item.content.firstMessage.id.peerId {
return false
}
@ -495,7 +495,7 @@ public class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureReco
}
if let replyAttribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == replyAttribute.messageId.id {
} else {
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
}

View file

@ -363,7 +363,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
}
if let replyAttribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == replyAttribute.messageId.id {
} else {
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
}
@ -376,7 +376,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
}
if replyMessage != nil || replyForward != nil || replyStory != nil {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyMessage?.id {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == replyMessage?.id.id {
} else {
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
presentationData: item.presentationData,

View file

@ -234,7 +234,7 @@ public func isPollEffectivelyClosed(message: Message, poll: TelegramMediaPoll) -
public extension ChatReplyThreadMessage {
var effectiveTopId: MessageId {
return self.channelMessageId ?? self.messageId
return self.channelMessageId ?? MessageId(peerId: self.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: self.threadId))
}
}

View file

@ -253,7 +253,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
return false
}
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.messageId.peerId != item.content.firstMessage.id.peerId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.peerId != item.content.firstMessage.id.peerId {
return false
}
@ -466,8 +466,8 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
hasAvatar = true
}
case let .replyThread(replyThreadMessage):
if replyThreadMessage.messageId.peerId != item.context.account.peerId {
if replyThreadMessage.messageId.peerId.isGroupOrChannel && item.message.author != nil {
if replyThreadMessage.peerId != item.context.account.peerId {
if replyThreadMessage.peerId.isGroupOrChannel && item.message.author != nil {
var isBroadcastChannel = false
if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
isBroadcastChannel = true
@ -689,7 +689,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
if let replyAttribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == replyAttribute.messageId.id {
} else {
replyMessage = item.message.associatedMessages[replyAttribute.messageId]
}

View file

@ -44,6 +44,10 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
private var presentationDataDisposable: Disposable?
private let chatListNode: ChatListNode
private var emptyShimmerEffectNode: ChatListShimmerNode?
private var shimmerNodeOffset: CGFloat = 0.0
private var floatingHeaderOffset: CGFloat?
public init(context: AccountContext, navigationController: @escaping () -> NavigationController?) {
self.context = context
@ -94,10 +98,7 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
navigationController: navigationController,
context: self.context,
chatLocation: .replyThread(ChatReplyThreadMessage(
messageId: makeThreadIdMessageId(
peerId: self.context.account.peerId,
threadId: peer.id.toInt64()
),
peerId: self.context.account.peerId,
threadId: peer.id.toInt64(),
channelMessageId: nil,
isChannelPost: false,
@ -115,6 +116,53 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
))
self.chatListNode.clearHighlightAnimated(true)
}
self.chatListNode.isEmptyUpdated = { [weak self] isEmptyState, _, transition in
guard let self else {
return
}
var needsShimmerNode = false
let shimmerNodeOffset: CGFloat = 0.0
switch isEmptyState {
case let .empty(isLoadingValue, _):
if isLoadingValue {
needsShimmerNode = true
}
case .notEmpty:
break
}
if needsShimmerNode {
self.shimmerNodeOffset = shimmerNodeOffset
if self.emptyShimmerEffectNode == nil {
let emptyShimmerEffectNode = ChatListShimmerNode()
self.emptyShimmerEffectNode = emptyShimmerEffectNode
self.insertSubnode(emptyShimmerEffectNode, belowSubnode: self.chatListNode)
if let currentParams = self.currentParams, let offset = self.floatingHeaderOffset {
self.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: currentParams.size, insets: UIEdgeInsets(top: currentParams.topInset, left: currentParams.sideInset, bottom: currentParams.bottomInset, right: currentParams.sideInset), verticalOffset: offset + self.shimmerNodeOffset, transition: .immediate)
}
}
} else if let emptyShimmerEffectNode = self.emptyShimmerEffectNode {
self.emptyShimmerEffectNode = nil
let emptyNodeTransition = transition.isAnimated ? transition : .animated(duration: 0.3, curve: .easeInOut)
emptyNodeTransition.updateAlpha(node: emptyShimmerEffectNode, alpha: 0.0, completion: { [weak emptyShimmerEffectNode] _ in
emptyShimmerEffectNode?.removeFromSupernode()
})
self.chatListNode.alpha = 0.0
emptyNodeTransition.updateAlpha(node: self.chatListNode, alpha: 1.0)
}
}
self.chatListNode.updateFloatingHeaderOffset = { [weak self] offset, transition in
guard let self else {
return
}
self.floatingHeaderOffset = offset
if let currentParams = self.currentParams, let emptyShimmerEffectNode = self.emptyShimmerEffectNode {
self.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: currentParams.size, insets: UIEdgeInsets(top: currentParams.topInset, left: currentParams.sideInset, bottom: currentParams.bottomInset, right: currentParams.sideInset), verticalOffset: offset + self.shimmerNodeOffset, transition: transition)
}
}
}
deinit {
@ -164,6 +212,11 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
return true
}
private func layoutEmptyShimmerEffectNode(node: ChatListShimmerNode, size: CGSize, insets: UIEdgeInsets, verticalOffset: CGFloat, transition: ContainedViewLayoutTransition) {
node.update(context: self.context, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, size: size, isInlineMode: false, presentationData: self.presentationData, transition: .immediate)
transition.updateFrameAdditive(node: node, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOffset), size: size))
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer.state != .failed, let otherGestureRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer {
let _ = otherGestureRecognizer

View file

@ -830,9 +830,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
/*if peerId == context.account.peerId, case .peer = chatLocation {
if peerId == context.account.peerId, case .peer = chatLocation {
availablePanes?.insert(.savedMessagesChats, at: 0)
}*/
}
} else {
availablePanes = nil
}

View file

@ -450,7 +450,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var currentPanelStatusData: PeerInfoStatusData?
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) -> CGFloat {
var threadData = threadData
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
threadData = nil
}
@ -1606,7 +1606,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isSettings {
expandablePart += 20.0
} else {
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
expandablePart = 0.0
} else if peer?.id == self.context.account.peerId {
expandablePart = 0.0

View file

@ -6009,7 +6009,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
private func openChatWithMessageSearch() {
if let navigationController = (self.controller?.navigationController as? NavigationController) {
if case let .replyThread(currentMessage) = self.chatLocation, let current = navigationController.viewControllers.first(where: { controller in
if let controller = controller as? ChatController, case let .replyThread(message) = controller.chatLocation, message.messageId == currentMessage.messageId {
if let controller = controller as? ChatController, case let .replyThread(message) = controller.chatLocation, message.peerId == currentMessage.peerId, message.threadId == currentMessage.threadId {
return true
}
return false
@ -10922,7 +10922,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
let navigateChatLocation: NavigateToChatControllerParams.Location
if let threadId = item.threadId {
navigateChatLocation = .replyThread(ChatReplyThreadMessage(
messageId: MessageId(peerId: item.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
peerId: item.peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
))
} else {
navigateChatLocation = .peer(itemPeer)

View file

@ -2563,7 +2563,7 @@ final class StorageUsageScreenComponent: Component {
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
chatLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
}
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
@ -2666,7 +2666,7 @@ final class StorageUsageScreenComponent: Component {
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
chatLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
}
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(

View file

@ -477,11 +477,11 @@ public final class AccountContextImpl: AccountContext {
case let .peer(peerId):
return .peer(peerId: peerId, threadId: nil)
case let .replyThread(data):
if data.isForumPost {
return .peer(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
if data.isForumPost || data.peerId.namespace != Namespaces.Peer.CloudChannel {
return .peer(peerId: data.peerId, threadId: data.threadId)
} else {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state)
return .thread(peerId: data.peerId, threadId: data.threadId, data: context.state)
}
case .feed:
preconditionFailure()
@ -494,7 +494,7 @@ public final class AccountContextImpl: AccountContext {
return .single(nil)
case let .replyThread(data):
if data.isForumPost, let peerId = location.peerId {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.peerId, threadId: data.threadId)
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> MessageId? in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.data.get(MessageHistoryThreadData.self) {
@ -503,9 +503,11 @@ public final class AccountContextImpl: AccountContext {
return nil
}
}
} else {
} else if data.peerId.namespace == Namespaces.Peer.CloudChannel {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.maxReadOutgoingMessageId
} else {
return .single(nil)
}
case .feed:
return .single(nil)
@ -530,7 +532,7 @@ public final class AccountContextImpl: AccountContext {
}
case let .replyThread(data):
if data.isForumPost {
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.messageId.peerId, threadId: Int64(data.messageId.id))
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: data.peerId, threadId: data.threadId)
return self.account.postbox.combinedView(keys: [viewKey])
|> map { views -> Int in
if let threadInfo = views.views[viewKey] as? MessageHistoryThreadInfoView, let data = threadInfo.info?.data.get(MessageHistoryThreadData.self) {
@ -539,6 +541,8 @@ public final class AccountContextImpl: AccountContext {
return 0
}
}
} else if data.peerId.namespace != Namespaces.Peer.CloudChannel {
return .single(0)
} else {
let context = chatLocationContext(holder: contextHolder, account: self.account, data: data)
return context.unreadCount
@ -722,7 +726,7 @@ private final class ChatLocationReplyContextHolderImpl: ChatLocationContextHolde
let context: ReplyThreadHistoryContext
init(account: Account, data: ChatReplyThreadMessage) {
self.context = ReplyThreadHistoryContext(account: account, peerId: data.messageId.peerId, data: data)
self.context = ReplyThreadHistoryContext(account: account, peerId: data.peerId, data: data)
}
}

View file

@ -313,7 +313,7 @@ final class AuthorizedApplicationContext {
let chatLocation: NavigateToChatControllerParams.Location
if let _ = threadData, let threadId = firstMessage.threadId {
chatLocation = .replyThread(ChatReplyThreadMessage(
messageId: MessageId(peerId: firstMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
peerId: firstMessage.id.peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
).normalized)
} else {
guard let peer = firstMessage.peers[firstMessage.id.peerId] else {
@ -905,7 +905,7 @@ final class AuthorizedApplicationContext {
let chatLocation: NavigateToChatControllerParams.Location
if let threadId = threadId {
chatLocation = .replyThread(ChatReplyThreadMessage(
messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
peerId: peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
))
} else {
chatLocation = .peer(peer)

View file

@ -18,9 +18,9 @@ extension ChatControllerImpl {
params: NavigateToMessageParams
) {
var id = id
if case let .replyThread(message) = self.chatLocation {
if case let .replyThread(message) = self.chatLocation, let effectiveMessageId = message.effectiveMessageId {
if let channelMessageId = message.channelMessageId, id == channelMessageId {
id = message.messageId
id = effectiveMessageId
}
}
@ -130,7 +130,7 @@ extension ChatControllerImpl {
let navigateToLocation: NavigateToChatControllerParams.Location
if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
navigateToLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
} else {
navigateToLocation = .peer(peer)
}
@ -148,7 +148,7 @@ extension ChatControllerImpl {
if let navigationController = self.effectiveNavigationController {
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let message = message, let threadId = message.threadId {
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
chatLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
}
var quote: ChatControllerSubject.MessageHighlight.Quote?
@ -221,7 +221,7 @@ extension ChatControllerImpl {
let searchLocation: ChatHistoryInitialSearchLocation
switch messageLocation {
case let .id(id, _):
if case let .replyThread(message) = self.chatLocation, id == message.messageId {
if case let .replyThread(message) = self.chatLocation, id == message.effectiveMessageId {
searchLocation = .index(.absoluteLowerBound())
} else {
searchLocation = .id(id)

View file

@ -608,13 +608,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
locationBroadcastPanelSource = .none
groupCallPanelSource = .none
let promise = Promise<Message?>()
promise.set(context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: replyThreadMessage.messageId))
|> map { message -> Message? in
guard let message = message else {
return nil
}
return message._asMessage()
})
if let effectiveMessageId = replyThreadMessage.effectiveMessageId {
promise.set(context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: effectiveMessageId))
|> map { message -> Message? in
guard let message = message else {
return nil
}
return message._asMessage()
})
} else {
promise.set(.single(nil))
}
self.chatLocationInfoData = .replyThread(promise)
case .feed:
locationBroadcastPanelSource = .none
@ -1038,11 +1042,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
let openChatLocation = strongSelf.chatLocation
/*if case let .replyThread(replyThreadMessage) = openChatLocation {
if message.threadId != makeMessageThreadId(replyThreadMessage.messageId) {
openChatLocation = .peer(id: message.id.peerId)
}
}*/
return context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, updatedPresentationData: strongSelf.updatedPresentationData, chatLocation: openChatLocation, chatLocationContextHolder: strongSelf.chatLocationContextHolder, message: message, standalone: false, reverseMessageGalleryOrder: false, mode: mode, navigationController: strongSelf.effectiveNavigationController, dismissInput: {
self?.chatDisplayNode.dismissInput()
@ -2804,12 +2803,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if isCopyLink, let channel = channel as? TelegramChannel {
var threadMessageId: MessageId?
var threadId: Int64?
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
threadMessageId = replyThreadMessage.messageId
threadId = replyThreadMessage.threadId
}
let _ = (context.engine.messages.exportMessageLink(peerId: messageId.peerId, messageId: messageId, isThread: threadMessageId != nil)
let _ = (context.engine.messages.exportMessageLink(peerId: messageId.peerId, messageId: messageId, isThread: threadId != nil)
|> map { result -> String? in
return result
}
@ -2995,7 +2994,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
if let strongSelf = self {
if case let .replyThread(replyThreadMessage) = strongSelf.chatLocation, replyThreadMessage.messageId == message.id {
if case let .replyThread(replyThreadMessage) = strongSelf.chatLocation, replyThreadMessage.effectiveMessageId == message.id {
return .none
}
if case .peer = strongSelf.chatLocation, let channel = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum) {
@ -3027,7 +3026,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
}
case let .replyThread(replyThreadMessage):
let peerId = replyThreadMessage.messageId.peerId
let peerId = replyThreadMessage.peerId
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, forceInCurrentChat: true, animated: true, completion: nil)
case .feed:
break
@ -5705,7 +5704,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .peer:
replyThreadType = .replies
case let .replyThread(replyThreadMessage):
if replyThreadMessage.messageId.peerId == context.account.peerId {
if replyThreadMessage.peerId == context.account.peerId {
replyThreadId = replyThreadMessage.threadId
replyThreadType = .replies
} else {
@ -5751,8 +5750,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
let savedMessagesPeerId: PeerId?
if case let .replyThread(replyThreadMessage) = chatLocation, replyThreadMessage.messageId.peerId == context.account.peerId {
savedMessagesPeerId = PeerId(makeMessageThreadId(replyThreadMessage.messageId))
if case let .replyThread(replyThreadMessage) = chatLocation, replyThreadMessage.peerId == context.account.peerId {
savedMessagesPeerId = PeerId(replyThreadMessage.threadId)
} else {
savedMessagesPeerId = nil
}
@ -6302,7 +6301,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case let .peer(peerId):
activitySpace = PeerActivitySpace(peerId: peerId, category: .global)
case let .replyThread(replyThreadMessage):
activitySpace = PeerActivitySpace(peerId: replyThreadMessage.messageId.peerId, category: .thread(makeMessageThreadId(replyThreadMessage.messageId)))
activitySpace = PeerActivitySpace(peerId: replyThreadMessage.peerId, category: .thread(replyThreadMessage.threadId))
case .feed:
activitySpace = nil
}
@ -6868,7 +6867,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let chatLocation: ChatLocation
if let threadId {
chatLocation = .replyThread(message: ChatReplyThreadMessage(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
chatLocation = .replyThread(message: ChatReplyThreadMessage(peerId: peerId, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
} else {
chatLocation = .peer(id: peerId)
}
@ -7176,7 +7175,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var closeOnEmpty = false
if case .pinnedMessages = self.presentationInterfaceState.subject {
closeOnEmpty = true
} else if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
} else if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
closeOnEmpty = true
}
@ -10999,7 +10998,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case let .peer(peerId):
activitySpace = PeerActivitySpace(peerId: peerId, category: .global)
case let .replyThread(replyThreadMessage):
activitySpace = PeerActivitySpace(peerId: replyThreadMessage.messageId.peerId, category: .thread(makeMessageThreadId(replyThreadMessage.messageId)))
activitySpace = PeerActivitySpace(peerId: replyThreadMessage.peerId, category: .thread(replyThreadMessage.threadId))
case .feed:
activitySpace = nil
}
@ -11315,7 +11314,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if case let .replyThread(message) = self.chatLocation, message.isForumPost {
if self.keepMessageCountersSyncrhonizedDisposable == nil {
self.keepMessageCountersSyncrhonizedDisposable = self.context.engine.messages.keepMessageCountersSyncrhonized(peerId: message.messageId.peerId, threadId: Int64(message.messageId.id)).startStrict()
self.keepMessageCountersSyncrhonizedDisposable = self.context.engine.messages.keepMessageCountersSyncrhonized(peerId: message.peerId, threadId: message.threadId).startStrict()
}
}
@ -11851,8 +11850,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case let .peer(peerIdValue):
peerId = peerIdValue
case let .replyThread(replyThreadMessage):
peerId = replyThreadMessage.messageId.peerId
threadId = makeMessageThreadId(replyThreadMessage.messageId)
peerId = replyThreadMessage.peerId
threadId = replyThreadMessage.threadId
case .feed:
return
}
@ -12392,7 +12391,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}))
case .replyThread:
if let peer = self.presentationInterfaceState.renderedPeer?.peer, case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
if let peer = self.presentationInterfaceState.renderedPeer?.peer, case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: peer, mode: .forumTopic(thread: replyThreadMessage), avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) {
self.effectiveNavigationController?.pushViewController(infoController)
}
@ -14948,7 +14947,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .peer:
break
case let .replyThread(replyThreadMessage):
defaultReplyMessageSubject = EngineMessageReplySubject(messageId: replyThreadMessage.messageId, quote: nil)
if let effectiveMessageId = replyThreadMessage.effectiveMessageId {
defaultReplyMessageSubject = EngineMessageReplySubject(messageId: effectiveMessageId, quote: nil)
}
case .feed:
break
}
@ -15651,22 +15652,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
return nil
}
var searchTopMsgId: MessageId?
var threadId: Int64?
switch self.chatLocation {
case .peer:
break
case let .replyThread(replyThreadMessage):
searchTopMsgId = replyThreadMessage.messageId
threadId = replyThreadMessage.threadId
case .feed:
break
}
switch search.domain {
case .everything:
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: nil, tags: nil, topMsgId: searchTopMsgId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: nil, tags: nil, threadId: threadId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
case .members:
derivedSearchState = nil
case let .member(peer):
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: peer.id, tags: nil, topMsgId: searchTopMsgId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: peer.id, tags: nil, threadId: threadId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
}
}
@ -15972,8 +15973,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
peerId = peerIdValue
threadId = nil
case let .replyThread(replyThreadMessage):
peerId = replyThreadMessage.messageId.peerId
threadId = makeMessageThreadId(replyThreadMessage.messageId)
peerId = replyThreadMessage.peerId
threadId = replyThreadMessage.threadId
case .feed:
return
}
@ -16009,8 +16010,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
peerId = peerIdValue
threadId = nil
case let .replyThread(replyThreadMessage):
peerId = replyThreadMessage.messageId.peerId
threadId = makeMessageThreadId(replyThreadMessage.messageId)
peerId = replyThreadMessage.peerId
threadId = replyThreadMessage.threadId
case .feed:
return
}

View file

@ -383,7 +383,7 @@ private func extractAssociatedData(
}
}
} else if case let .replyThread(message) = chatLocation, message.isForumPost {
automaticDownloadPeerId = message.messageId.peerId
automaticDownloadPeerId = message.peerId
}
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadPeerId: automaticDownloadPeerId, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, topicAuthorId: topicAuthorId, hasBots: hasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes)
@ -1145,11 +1145,11 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
additionalData.append(.totalUnreadState)
}
if case let .replyThread(replyThreadMessage) = self.chatLocation {
additionalData.append(.cachedPeerData(replyThreadMessage.messageId.peerId))
additionalData.append(.peerNotificationSettings(replyThreadMessage.messageId.peerId))
if replyThreadMessage.messageId.peerId.namespace == Namespaces.Peer.CloudChannel {
additionalData.append(.cacheEntry(cachedChannelAdminRanksEntryId(peerId: replyThreadMessage.messageId.peerId)))
additionalData.append(.peer(replyThreadMessage.messageId.peerId))
additionalData.append(.cachedPeerData(replyThreadMessage.peerId))
additionalData.append(.peerNotificationSettings(replyThreadMessage.peerId))
if replyThreadMessage.peerId.namespace == Namespaces.Peer.CloudChannel {
additionalData.append(.cacheEntry(cachedChannelAdminRanksEntryId(peerId: replyThreadMessage.peerId)))
additionalData.append(.peer(replyThreadMessage.peerId))
}
additionalData.append(.message(replyThreadMessage.effectiveTopId))

View file

@ -718,7 +718,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
let readCounters: Signal<Bool, NoError>
if case let .replyThread(threadMessage) = chatPresentationInterfaceState.chatLocation, threadMessage.isForumPost {
readCounters = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThreadData(id: threadMessage.messageId.peerId, threadId: Int64(threadMessage.messageId.id)))
readCounters = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThreadData(id: threadMessage.peerId, threadId: threadMessage.threadId))
|> map { threadData -> Bool in
guard let threadData else {
return false
@ -1248,7 +1248,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} else {
for attribute in messages[0].attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, attribute.count > 0 {
threadId = makeMessageThreadId(messages[0].id)
threadId = Int64(messages[0].id.id)
threadMessageCount = Int(attribute.count)
}
}
@ -1256,7 +1256,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} else {
for attribute in messages[0].attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, attribute.count > 0 {
threadId = makeMessageThreadId(messages[0].id)
threadId = Int64(messages[0].id.id)
threadMessageCount = Int(attribute.count)
}
}
@ -1404,7 +1404,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}, action: { _, f in
var threadMessageId: MessageId?
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
threadMessageId = replyThreadMessage.messageId
threadMessageId = replyThreadMessage.effectiveMessageId
}
let _ = (context.engine.messages.exportMessageLink(peerId: message.id.peerId, messageId: message.id, isThread: threadMessageId != nil)
|> map { result -> String? in

View file

@ -117,7 +117,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
}
}
if case let .replyThread(message) = chatPresentationInterfaceState.chatLocation, message.messageId.peerId == context.account.peerId {
if case let .replyThread(message) = chatPresentationInterfaceState.chatLocation, message.peerId == context.account.peerId {
if let currentPanel = (currentPanel as? ChatChannelSubscriberInputPanelNode) ?? (currentSecondaryPanel as? ChatChannelSubscriberInputPanelNode) {
return (currentPanel, nil)
} else {

View file

@ -71,7 +71,7 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
}
}
if case let .replyThread(message) = presentationInterfaceState.chatLocation, message.messageId.peerId == context.account.peerId {
if case let .replyThread(message) = presentationInterfaceState.chatLocation, message.peerId == context.account.peerId {
return chatInfoNavigationButton
}

View file

@ -268,7 +268,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
return true
}
case let .replyThread(replyThreadMessage):
if message.id.peerId == replyThreadMessage.messageId.peerId {
if message.id.peerId == replyThreadMessage.peerId {
return true
}
}

View file

@ -206,10 +206,10 @@ func openResolvedUrlImpl(
case let .channelMessage(peer, messageId, timecode):
openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: timecode), peekData: nil))
case let .replyThreadMessage(replyThreadMessage, messageId):
if let navigationController = navigationController {
if let navigationController = navigationController, let effectiveMessageId = replyThreadMessage.effectiveMessageId {
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in
present(c, a)
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).startStandalone()
}, messageId: effectiveMessageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).startStandalone()
}
case let .replyThread(messageId):
if let navigationController = navigationController {

View file

@ -72,10 +72,10 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(EnginePeer(peer)), subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: timecode)))
}
case let .replyThreadMessage(replyThreadMessage, messageId):
if let navigationController = controller.navigationController as? NavigationController {
if let navigationController = controller.navigationController as? NavigationController, let effectiveMessageId = replyThreadMessage.effectiveMessageId {
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
}, messageId: effectiveMessageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
}
case let .replyThread(messageId):
if let navigationController = controller.navigationController as? NavigationController {

View file

@ -719,7 +719,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .progress
case let .result(info):
if let _ = info {
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(peerId: channel.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
} else {
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
}
@ -744,7 +744,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .progress
case let .result(info):
if let _ = info {
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: replyThreadMessageId.id)), threadId: Int64(replyThreadMessageId.id), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: replyId)))
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(peerId: channel.id, threadId: Int64(replyThreadMessageId.id), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: replyId)))
} else {
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
}
@ -760,7 +760,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
guard let result = result else {
return .result(.channelMessage(peer: peer._asPeer(), messageId: replyThreadMessageId, timecode: nil))
}
return .result(.replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.messageId.peerId, namespace: Namespaces.Message.Cloud, id: replyId)))
return .result(.replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.peerId, namespace: Namespaces.Message.Cloud, id: replyId)))
})
}
case let .voiceChat(invite):
@ -825,7 +825,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .progress
case let .result(info):
if let _ = info {
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: Int64(threadId), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(peerId: channel.id, threadId: Int64(threadId), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
} else {
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
}
@ -849,7 +849,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .progress
case let .result(info):
if let _ = info {
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(peerId: channel.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
} else {
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
}