diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index e66a33337f..7514260687 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -14,6 +14,12 @@ public struct Namespaces { public static let allScheduled: Set = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal]) public static let allQuickReply: Set = Set([Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal]) public static let allNonRegular: Set = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal, Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal]) + public static let allLocal: [Int32] = [ + Namespaces.Message.Local, + Namespaces.Message.SecretIncoming, + Namespaces.Message.ScheduledLocal, + Namespaces.Message.QuickReplyLocal + ] } public struct Media { diff --git a/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift b/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift index 809deb1ba6..79be541f9a 100644 --- a/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift +++ b/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift @@ -43,7 +43,7 @@ public struct ChatMessageEntryAttributes: Equatable { public enum ChatHistoryEntry: Identifiable, Comparable { case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes) - case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)], ChatPresentationData) + case MessageGroupEntry(Int64, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)], ChatPresentationData) case UnreadEntry(MessageIndex, ChatPresentationData) case ReplyCountEntry(MessageIndex, Bool, Int, ChatPresentationData) case ChatInfoEntry(String, String, TelegramMediaImage?, TelegramMediaFile?, ChatPresentationData) @@ -63,7 +63,7 @@ public enum ChatHistoryEntry: Identifiable, Comparable { } return UInt64(message.stableId) | ((type << 40)) case let .MessageGroupEntry(groupInfo, _, _): - return UInt64(groupInfo.stableId) | ((UInt64(2) << 40)) + return UInt64(bitPattern: groupInfo) | ((UInt64(2) << 40)) case .UnreadEntry: return UInt64(4) << 40 case .ReplyCountEntry: diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index 4296bab4e6..d11043b5ae 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -12,7 +12,28 @@ import TextFormat import Markdown import Display +struct ChatHistoryEntriesForViewState { + private var messageStableIdToLocalId: [UInt32: Int64] = [:] + + init() { + } + + mutating func messageGroupStableId(messageStableId: UInt32, groupId: Int64, isLocal: Bool) -> Int64 { + if isLocal { + self.messageStableIdToLocalId[messageStableId] = groupId + return groupId + } else { + if let value = self.messageStableIdToLocalId[messageStableId] { + return value + } else { + return groupId + } + } + } +} + func chatHistoryEntriesForView( + currentState: ChatHistoryEntriesForViewState, context: AccountContext, location: ChatLocation, view: MessageHistoryView, @@ -37,9 +58,11 @@ func chatHistoryEntriesForView( cachedData: CachedPeerData?, adMessage: Message?, dynamicAdMessages: [Message] -) -> [ChatHistoryEntry] { +) -> ([ChatHistoryEntry], ChatHistoryEntriesForViewState) { + var currentState = currentState + if historyAppearsCleared { - return [] + return ([], currentState) } var entries: [ChatHistoryEntry] = [] var adminRanks: [PeerId: CachedChannelAdminRank] = [:] @@ -121,8 +144,8 @@ func chatHistoryEntriesForView( } } - var existingGroupStableIds: [UInt32] = [] - var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = [] + //var existingGroupStableIds: [UInt32] = [] + //var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = [] var count = 0 loop: for entry in view.entries { var message = entry.message @@ -199,7 +222,7 @@ func chatHistoryEntriesForView( } if groupMessages || reverseGroupedMessages { - if !groupBucket.isEmpty && message.groupInfo != groupBucket[0].0.groupInfo { + /*if !groupBucket.isEmpty && message.groupInfo != groupBucket[0].0.groupInfo { if reverseGroupedMessages { groupBucket.reverse() } @@ -215,15 +238,61 @@ func chatHistoryEntriesForView( } } groupBucket.removeAll() - } - if let _ = message.groupInfo { + }*/ + if let messageGroupingKey = message.groupingKey, (groupMessages || reverseGroupedMessages) { let selection: ChatHistoryMessageSelection if let selectedMessages = selectedMessages { selection = .selectable(selected: selectedMessages.contains(message.id)) } else { selection = .none } - groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }), entry.location)) + + var isCentered = false + if case let .messageOptions(_, _, info) = associatedData.subject, case let .link(link) = info { + isCentered = link.isCentered + } + + let attributes = ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: isCentered, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }) + + let groupStableId = currentState.messageGroupStableId(messageStableId: message.stableId, groupId: messageGroupingKey, isLocal: Namespaces.Message.allLocal.contains(message.id.namespace)) + var found = false + for i in 0 ..< entries.count { + if case let .MessageEntry(currentMessage, _, currentIsRead, currentLocation, currentSelection, currentAttributes) = entries[i], let currentGroupingKey = currentMessage.groupingKey, currentState.messageGroupStableId(messageStableId: currentMessage.stableId, groupId: currentGroupingKey, isLocal: Namespaces.Message.allLocal.contains(currentMessage.id.namespace)) == groupStableId { + found = true + + var currentMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = [] + + currentMessages.append((currentMessage, currentIsRead, currentSelection, currentAttributes, currentLocation)) + if reverseGroupedMessages { + currentMessages.insert((message, isRead, selection, attributes, entry.location), at: 0) + } else { + currentMessages.append((message, isRead, selection, attributes, entry.location)) + } + + entries[i] = .MessageGroupEntry(groupStableId, currentMessages, presentationData) + } else if case let .MessageGroupEntry(currentGroupStableId, currentMessages, _) = entries[i], currentGroupStableId == groupStableId { + found = true + + var currentMessages = currentMessages + if reverseGroupedMessages { + currentMessages.insert((message, isRead, selection, attributes, entry.location), at: 0) + } else { + currentMessages.append((message, isRead, selection, attributes, entry.location)) + } + entries[i] = .MessageGroupEntry(currentGroupStableId, currentMessages, presentationData) + } + } + if !found { + entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, attributes)) + } + + /*let selection: ChatHistoryMessageSelection + if let selectedMessages = selectedMessages { + selection = .selectable(selected: selectedMessages.contains(message.id)) + } else { + selection = .none + } + groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }), entry.location))*/ } else { let selection: ChatHistoryMessageSelection if let selectedMessages = selectedMessages { @@ -250,7 +319,7 @@ func chatHistoryEntriesForView( } } - if !groupBucket.isEmpty { + /*if !groupBucket.isEmpty { assert(groupMessages || reverseGroupedMessages) if reverseGroupedMessages { groupBucket.reverse() @@ -266,7 +335,7 @@ func chatHistoryEntriesForView( entries.append(.MessageEntry(message, presentationData, isRead, location, selection, attributes)) } } - } + }*/ if let lowerTimestamp = view.entries.last?.message.timestamp, let upperTimestamp = view.entries.first?.message.timestamp { if let joinMessage { @@ -341,12 +410,12 @@ func chatHistoryEntriesForView( } addedThreadHead = true - if messages.count > 1, let groupInfo = messages[0].groupInfo { + if messages.count > 1, let groupingKey = messages[0].groupingKey { var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = [] for message in messages { groupMessages.append((message, false, .none, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }), nil)) } - entries.insert(.MessageGroupEntry(groupInfo, groupMessages, presentationData), at: 0) + entries.insert(.MessageGroupEntry(groupingKey, groupMessages, presentationData), at: 0) } else { if !hasTopicCreated { entries.insert(.MessageEntry(messages[0], presentationData, false, nil, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[messages[0].id], isPlaying: false, isCentered: false, authorStoryStats: messages[0].author.flatMap { view.peerStoryStats[$0.id] })), at: 0) @@ -583,8 +652,8 @@ func chatHistoryEntriesForView( } if reverse { - return entries.reversed() + return (entries.reversed(), currentState) } else { - return entries + return (entries, currentState) } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 14eb04a204..7d9993a2f2 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1419,6 +1419,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } |> distinctUntilChanged + let chatHistoryEntriesForViewState = Atomic(value: ChatHistoryEntriesForViewState()) + let animatedEmojiStickers: Signal<[String: [StickerPackItem]], NoError> = context.animatedEmojiStickers let additionalAnimatedEmojiStickers = context.additionalAnimatedEmojiStickers @@ -1857,7 +1859,10 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto includeEmbeddedSavedChatInfo = true } - let filteredEntries = chatHistoryEntriesForView( + let previousChatHistoryEntriesForViewState = chatHistoryEntriesForViewState.with({ $0 }) + + let (filteredEntries, updatedChatHistoryEntriesForViewState) = chatHistoryEntriesForView( + currentState: previousChatHistoryEntriesForViewState, context: context, location: chatLocation, view: view, @@ -1886,6 +1891,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto let lastHeaderId = filteredEntries.last.flatMap { listMessageDateHeaderId(timestamp: $0.index.timestamp) } ?? 0 let processedView = ChatHistoryView(originalView: view, filteredEntries: filteredEntries, associatedData: associatedData, lastHeaderId: lastHeaderId, id: id, locationInput: update.2, ignoreMessagesInTimestampRange: update.3, ignoreMessageIds: update.4) let previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages, allAdMessages.version)) + let _ = chatHistoryEntriesForViewState.swap(updatedChatHistoryEntriesForViewState) let previous = previousValueAndVersion?.0 let previousSelectedMessages = previousValueAndVersion?.2