Update message group rendering

This commit is contained in:
Isaac 2024-07-16 10:16:25 +08:00
parent 7b7b403c00
commit dd457ae82f
4 changed files with 98 additions and 17 deletions

View File

@ -14,6 +14,12 @@ public struct Namespaces {
public static let allScheduled: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal]) public static let allScheduled: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal])
public static let allQuickReply: Set<Int32> = Set([Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal]) public static let allQuickReply: Set<Int32> = Set([Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal])
public static let allNonRegular: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal, Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal]) public static let allNonRegular: Set<Int32> = 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 { public struct Media {

View File

@ -43,7 +43,7 @@ public struct ChatMessageEntryAttributes: Equatable {
public enum ChatHistoryEntry: Identifiable, Comparable { public enum ChatHistoryEntry: Identifiable, Comparable {
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes) 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 UnreadEntry(MessageIndex, ChatPresentationData)
case ReplyCountEntry(MessageIndex, Bool, Int, ChatPresentationData) case ReplyCountEntry(MessageIndex, Bool, Int, ChatPresentationData)
case ChatInfoEntry(String, String, TelegramMediaImage?, TelegramMediaFile?, ChatPresentationData) case ChatInfoEntry(String, String, TelegramMediaImage?, TelegramMediaFile?, ChatPresentationData)
@ -63,7 +63,7 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
} }
return UInt64(message.stableId) | ((type << 40)) return UInt64(message.stableId) | ((type << 40))
case let .MessageGroupEntry(groupInfo, _, _): case let .MessageGroupEntry(groupInfo, _, _):
return UInt64(groupInfo.stableId) | ((UInt64(2) << 40)) return UInt64(bitPattern: groupInfo) | ((UInt64(2) << 40))
case .UnreadEntry: case .UnreadEntry:
return UInt64(4) << 40 return UInt64(4) << 40
case .ReplyCountEntry: case .ReplyCountEntry:

View File

@ -12,7 +12,28 @@ import TextFormat
import Markdown import Markdown
import Display 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( func chatHistoryEntriesForView(
currentState: ChatHistoryEntriesForViewState,
context: AccountContext, context: AccountContext,
location: ChatLocation, location: ChatLocation,
view: MessageHistoryView, view: MessageHistoryView,
@ -37,9 +58,11 @@ func chatHistoryEntriesForView(
cachedData: CachedPeerData?, cachedData: CachedPeerData?,
adMessage: Message?, adMessage: Message?,
dynamicAdMessages: [Message] dynamicAdMessages: [Message]
) -> [ChatHistoryEntry] { ) -> ([ChatHistoryEntry], ChatHistoryEntriesForViewState) {
var currentState = currentState
if historyAppearsCleared { if historyAppearsCleared {
return [] return ([], currentState)
} }
var entries: [ChatHistoryEntry] = [] var entries: [ChatHistoryEntry] = []
var adminRanks: [PeerId: CachedChannelAdminRank] = [:] var adminRanks: [PeerId: CachedChannelAdminRank] = [:]
@ -121,8 +144,8 @@ func chatHistoryEntriesForView(
} }
} }
var existingGroupStableIds: [UInt32] = [] //var existingGroupStableIds: [UInt32] = []
var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = [] //var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
var count = 0 var count = 0
loop: for entry in view.entries { loop: for entry in view.entries {
var message = entry.message var message = entry.message
@ -199,7 +222,7 @@ func chatHistoryEntriesForView(
} }
if groupMessages || reverseGroupedMessages { if groupMessages || reverseGroupedMessages {
if !groupBucket.isEmpty && message.groupInfo != groupBucket[0].0.groupInfo { /*if !groupBucket.isEmpty && message.groupInfo != groupBucket[0].0.groupInfo {
if reverseGroupedMessages { if reverseGroupedMessages {
groupBucket.reverse() groupBucket.reverse()
} }
@ -215,15 +238,61 @@ func chatHistoryEntriesForView(
} }
} }
groupBucket.removeAll() groupBucket.removeAll()
} }*/
if let _ = message.groupInfo { if let messageGroupingKey = message.groupingKey, (groupMessages || reverseGroupedMessages) {
let selection: ChatHistoryMessageSelection let selection: ChatHistoryMessageSelection
if let selectedMessages = selectedMessages { if let selectedMessages = selectedMessages {
selection = .selectable(selected: selectedMessages.contains(message.id)) selection = .selectable(selected: selectedMessages.contains(message.id))
} else { } else {
selection = .none 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 { } else {
let selection: ChatHistoryMessageSelection let selection: ChatHistoryMessageSelection
if let selectedMessages = selectedMessages { if let selectedMessages = selectedMessages {
@ -250,7 +319,7 @@ func chatHistoryEntriesForView(
} }
} }
if !groupBucket.isEmpty { /*if !groupBucket.isEmpty {
assert(groupMessages || reverseGroupedMessages) assert(groupMessages || reverseGroupedMessages)
if reverseGroupedMessages { if reverseGroupedMessages {
groupBucket.reverse() groupBucket.reverse()
@ -266,7 +335,7 @@ func chatHistoryEntriesForView(
entries.append(.MessageEntry(message, presentationData, isRead, location, selection, attributes)) 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 lowerTimestamp = view.entries.last?.message.timestamp, let upperTimestamp = view.entries.first?.message.timestamp {
if let joinMessage { if let joinMessage {
@ -341,12 +410,12 @@ func chatHistoryEntriesForView(
} }
addedThreadHead = true 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?)] = [] var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
for message in messages { 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)) 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 { } else {
if !hasTopicCreated { 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) 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 { if reverse {
return entries.reversed() return (entries.reversed(), currentState)
} else { } else {
return entries return (entries, currentState)
} }
} }

View File

@ -1419,6 +1419,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
} }
|> distinctUntilChanged |> distinctUntilChanged
let chatHistoryEntriesForViewState = Atomic<ChatHistoryEntriesForViewState>(value: ChatHistoryEntriesForViewState())
let animatedEmojiStickers: Signal<[String: [StickerPackItem]], NoError> = context.animatedEmojiStickers let animatedEmojiStickers: Signal<[String: [StickerPackItem]], NoError> = context.animatedEmojiStickers
let additionalAnimatedEmojiStickers = context.additionalAnimatedEmojiStickers let additionalAnimatedEmojiStickers = context.additionalAnimatedEmojiStickers
@ -1857,7 +1859,10 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
includeEmbeddedSavedChatInfo = true includeEmbeddedSavedChatInfo = true
} }
let filteredEntries = chatHistoryEntriesForView( let previousChatHistoryEntriesForViewState = chatHistoryEntriesForViewState.with({ $0 })
let (filteredEntries, updatedChatHistoryEntriesForViewState) = chatHistoryEntriesForView(
currentState: previousChatHistoryEntriesForViewState,
context: context, context: context,
location: chatLocation, location: chatLocation,
view: view, 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 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 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 previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages, allAdMessages.version))
let _ = chatHistoryEntriesForViewState.swap(updatedChatHistoryEntriesForViewState)
let previous = previousValueAndVersion?.0 let previous = previousValueAndVersion?.0
let previousSelectedMessages = previousValueAndVersion?.2 let previousSelectedMessages = previousValueAndVersion?.2