mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Better history-ad integration
This commit is contained in:
parent
554cd0e6fe
commit
efe0566b79
@ -689,6 +689,10 @@ public final class Message {
|
||||
self.associatedThreadInfo = associatedThreadInfo
|
||||
}
|
||||
|
||||
public func withUpdatedStableVersion(stableVersion: UInt32) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds, associatedMedia: self.associatedMedia, associatedThreadInfo: self.associatedThreadInfo)
|
||||
}
|
||||
|
||||
public func withUpdatedText(_ text: String) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds, associatedMedia: self.associatedMedia, associatedThreadInfo: self.associatedThreadInfo)
|
||||
}
|
||||
|
@ -4038,6 +4038,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})], parseMarkdown: true), in: .window(.root), with: nil)
|
||||
}
|
||||
})
|
||||
}, activateAdAction: { [weak self] messageId in
|
||||
guard let self, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId), let adAttribute = message.adAttribute else {
|
||||
return
|
||||
}
|
||||
|
||||
switch adAttribute.target {
|
||||
case let .peer(id, messageId, startParam):
|
||||
let navigationData: ChatControllerInteractionNavigateToPeer
|
||||
if let bot = message.author as? TelegramUser, bot.botInfo != nil, let startParam = startParam {
|
||||
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
|
||||
} else {
|
||||
var subject: ChatControllerSubject?
|
||||
if let messageId = messageId {
|
||||
subject = .message(id: .id(messageId), highlight: true, timecode: nil)
|
||||
}
|
||||
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
|
||||
}
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
if let self, let peer = peer {
|
||||
self.openPeer(peer: peer, navigation: navigationData, fromMessage: nil)
|
||||
}
|
||||
})
|
||||
case let .join(_, joinHash):
|
||||
self.controllerInteraction?.openJoinLink(joinHash)
|
||||
}
|
||||
}, requestMessageUpdate: { [weak self] id, scroll in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id, andScrollToItem: scroll)
|
||||
@ -6554,13 +6580,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var minOffsetForNavigation: CGFloat = 40.0
|
||||
strongSelf.chatDisplayNode.historyNode.enumerateItemNodes { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageBubbleItemNode {
|
||||
if let message = itemNode.item?.content.firstMessage, message.adAttribute != nil {
|
||||
if let message = itemNode.item?.content.firstMessage, let adAttribute = message.adAttribute {
|
||||
minOffsetForNavigation += itemNode.bounds.height
|
||||
|
||||
switch offset {
|
||||
case let .known(offset):
|
||||
if offset <= 50.0 {
|
||||
strongSelf.chatDisplayNode.historyNode.adSeenProcessingManager.add([message.id])
|
||||
strongSelf.chatDisplayNode.historyNode.markAdAsSeen(opaqueId: adAttribute.opaqueId)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
@ -141,6 +141,7 @@ public final class ChatControllerInteraction {
|
||||
let openLargeEmojiInfo: (String, String?, TelegramMediaFile) -> Void
|
||||
let openJoinLink: (String) -> Void
|
||||
let openWebView: (String, String, Bool, Bool) -> Void
|
||||
let activateAdAction: (EngineMessage.Id) -> Void
|
||||
|
||||
let requestMessageUpdate: (MessageId, Bool) -> Void
|
||||
let cancelInteractiveKeyboardGestures: () -> Void
|
||||
@ -248,6 +249,7 @@ public final class ChatControllerInteraction {
|
||||
openLargeEmojiInfo: @escaping (String, String?, TelegramMediaFile) -> Void,
|
||||
openJoinLink: @escaping (String) -> Void,
|
||||
openWebView: @escaping (String, String, Bool, Bool) -> Void,
|
||||
activateAdAction: @escaping (EngineMessage.Id) -> Void,
|
||||
requestMessageUpdate: @escaping (MessageId, Bool) -> Void,
|
||||
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
||||
dismissTextInput: @escaping () -> Void,
|
||||
@ -338,6 +340,7 @@ public final class ChatControllerInteraction {
|
||||
self.openLargeEmojiInfo = openLargeEmojiInfo
|
||||
self.openJoinLink = openJoinLink
|
||||
self.openWebView = openWebView
|
||||
self.activateAdAction = activateAdAction
|
||||
self.requestMessageUpdate = requestMessageUpdate
|
||||
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
|
||||
self.dismissTextInput = dismissTextInput
|
||||
|
@ -25,7 +25,7 @@ func chatHistoryEntriesForView(
|
||||
customChannelDiscussionReadState: MessageId?,
|
||||
customThreadOutgoingReadState: MessageId?,
|
||||
cachedData: CachedPeerData?,
|
||||
adMessages: (interPostInterval: Int32?, messages: [Message]),
|
||||
adMessage: Message?,
|
||||
dynamicAdMessages: [Message]
|
||||
) -> [ChatHistoryEntry] {
|
||||
if historyAppearsCleared {
|
||||
@ -339,36 +339,34 @@ func chatHistoryEntriesForView(
|
||||
}
|
||||
|
||||
if view.laterId == nil && !view.isLoading {
|
||||
if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], !adMessages.messages.isEmpty, adMessages.interPostInterval == nil {
|
||||
var nextAdMessageId: Int32 = 1
|
||||
if let message = adMessages.messages.first {
|
||||
let updatedMessage = Message(
|
||||
stableId: UInt32.max - 1 - UInt32(nextAdMessageId),
|
||||
stableVersion: message.stableVersion,
|
||||
id: MessageId(peerId: message.id.peerId, namespace: message.id.namespace, id: nextAdMessageId),
|
||||
globallyUniqueId: nil,
|
||||
groupingKey: nil,
|
||||
groupInfo: nil,
|
||||
threadId: nil,
|
||||
timestamp: lastMessage.timestamp,
|
||||
flags: message.flags,
|
||||
tags: message.tags,
|
||||
globalTags: message.globalTags,
|
||||
localTags: message.localTags,
|
||||
forwardInfo: message.forwardInfo,
|
||||
author: message.author,
|
||||
text: message.text,
|
||||
attributes: message.attributes,
|
||||
media: message.media,
|
||||
peers: message.peers,
|
||||
associatedMessages: message.associatedMessages,
|
||||
associatedMessageIds: message.associatedMessageIds,
|
||||
associatedMedia: message.associatedMedia,
|
||||
associatedThreadInfo: message.associatedThreadInfo
|
||||
)
|
||||
nextAdMessageId += 1
|
||||
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||
}
|
||||
if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], let message = adMessage {
|
||||
var nextAdMessageId: Int32 = 10000
|
||||
let updatedMessage = Message(
|
||||
stableId: ChatHistoryListNode.fixedAdMessageStableId,
|
||||
stableVersion: message.stableVersion,
|
||||
id: MessageId(peerId: message.id.peerId, namespace: message.id.namespace, id: nextAdMessageId),
|
||||
globallyUniqueId: nil,
|
||||
groupingKey: nil,
|
||||
groupInfo: nil,
|
||||
threadId: nil,
|
||||
timestamp: lastMessage.timestamp,
|
||||
flags: message.flags,
|
||||
tags: message.tags,
|
||||
globalTags: message.globalTags,
|
||||
localTags: message.localTags,
|
||||
forwardInfo: message.forwardInfo,
|
||||
author: message.author,
|
||||
text: /*"\(message.adAttribute!.opaqueId.hashValue)" + */message.text,
|
||||
attributes: message.attributes,
|
||||
media: message.media,
|
||||
peers: message.peers,
|
||||
associatedMessages: message.associatedMessages,
|
||||
associatedMessageIds: message.associatedMessageIds,
|
||||
associatedMedia: message.associatedMedia,
|
||||
associatedThreadInfo: message.associatedThreadInfo
|
||||
)
|
||||
nextAdMessageId += 1
|
||||
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||
}
|
||||
}
|
||||
} else if includeSearchEntry {
|
||||
|
@ -408,6 +408,8 @@ public enum ChatHistoryListSource {
|
||||
}
|
||||
|
||||
public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
static let fixedAdMessageStableId: UInt32 = UInt32.max - 5000
|
||||
|
||||
private let context: AccountContext
|
||||
private let chatLocation: ChatLocation
|
||||
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||
@ -495,7 +497,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
private let messageProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
private let messageWithReactionsProcessingManager = ChatMessageThrottledProcessingManager(submitInterval: 4.0)
|
||||
let adSeenProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
private let seenLiveLocationProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
private let unsupportedMessageProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
private let refreshMediaProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
@ -606,18 +607,20 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
private var contentInsetAnimator: DisplayLinkAnimator?
|
||||
|
||||
private let adMessagesContext: AdMessagesHistoryContext?
|
||||
private var adMessagesDisposable: Disposable?
|
||||
private var preloadAdPeerId: PeerId?
|
||||
private let preloadAdPeerDisposable = MetaDisposable()
|
||||
private var pendingDynamicAdMessages: [Message] = []
|
||||
private var pendingDynamicAdMessageInterval: Int?
|
||||
private var remainingDynamicAdMessageInterval: Int?
|
||||
private var remainingDynamicAdMessageDistance: CGFloat?
|
||||
private var nextPendingDynamicMessageId: Int32 = 1
|
||||
private var dynamicAdMessages: ([Message], Int) = ([], 0) {
|
||||
private var allAdMessages: (fixed: Message?, opportunistic: [Message], version: Int) = (nil, [], 0) {
|
||||
didSet {
|
||||
self.dynamicAdMessagesPromise.set(.single(self.dynamicAdMessages))
|
||||
self.allAdMessagesPromise.set(.single(self.allAdMessages))
|
||||
}
|
||||
}
|
||||
private let dynamicAdMessagesPromise = Promise<([Message], Int)>(([], 0))
|
||||
private let allAdMessagesPromise = Promise<(fixed: Message?, opportunistic: [Message], version: Int)>((nil, [], 0))
|
||||
private var seenMessageIds = Set<MessageId>()
|
||||
|
||||
private var refreshDisplayedItemRangeTimer: SwiftSignalKit.Timer?
|
||||
@ -686,35 +689,43 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
super.init()
|
||||
|
||||
adMessages = adMessages
|
||||
|> afterNext { [weak self] interPostInterval, messages in
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
self.adMessagesDisposable = (adMessages
|
||||
|> deliverOnMainQueue).start(next: { [weak self] interPostInterval, messages in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let interPostInterval = interPostInterval {
|
||||
self.pendingDynamicAdMessages = messages
|
||||
self.pendingDynamicAdMessageInterval = Int(interPostInterval)
|
||||
|
||||
if self.remainingDynamicAdMessageInterval == nil {
|
||||
self.remainingDynamicAdMessageInterval = Int(interPostInterval)
|
||||
}
|
||||
if self.remainingDynamicAdMessageDistance == nil {
|
||||
self.remainingDynamicAdMessageDistance = self.bounds.height
|
||||
}
|
||||
|
||||
if let interPostInterval = interPostInterval {
|
||||
strongSelf.pendingDynamicAdMessages = messages
|
||||
strongSelf.pendingDynamicAdMessageInterval = Int(interPostInterval)
|
||||
strongSelf.remainingDynamicAdMessageInterval = Int(interPostInterval)
|
||||
} else {
|
||||
var adPeerId: PeerId?
|
||||
adPeerId = messages.first?.author?.id
|
||||
|
||||
if strongSelf.preloadAdPeerId != adPeerId {
|
||||
strongSelf.preloadAdPeerId = adPeerId
|
||||
if let adPeerId = adPeerId {
|
||||
let combinedDisposable = DisposableSet()
|
||||
strongSelf.preloadAdPeerDisposable.set(combinedDisposable)
|
||||
combinedDisposable.add(strongSelf.context.account.viewTracker.polledChannel(peerId: adPeerId).start())
|
||||
combinedDisposable.add(strongSelf.context.account.addAdditionalPreloadHistoryPeerId(peerId: adPeerId))
|
||||
} else {
|
||||
strongSelf.preloadAdPeerDisposable.set(nil)
|
||||
}
|
||||
self.allAdMessages = (messages.first, [], 0)
|
||||
} else {
|
||||
var adPeerId: PeerId?
|
||||
adPeerId = messages.first?.author?.id
|
||||
|
||||
if self.preloadAdPeerId != adPeerId {
|
||||
self.preloadAdPeerId = adPeerId
|
||||
if let adPeerId = adPeerId {
|
||||
let combinedDisposable = DisposableSet()
|
||||
self.preloadAdPeerDisposable.set(combinedDisposable)
|
||||
combinedDisposable.add(self.context.account.viewTracker.polledChannel(peerId: adPeerId).start())
|
||||
combinedDisposable.add(self.context.account.addAdditionalPreloadHistoryPeerId(peerId: adPeerId))
|
||||
} else {
|
||||
self.preloadAdPeerDisposable.set(nil)
|
||||
}
|
||||
}
|
||||
|
||||
self.allAdMessages = (messages.first, [], 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.clipsToBounds = false
|
||||
|
||||
@ -737,16 +748,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.messageWithReactionsProcessingManager.process = { [weak context] messageIds in
|
||||
context?.account.viewTracker.updateReactionsForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
self.adSeenProcessingManager.process = { [weak self] messageIds in
|
||||
guard let strongSelf = self, let adMessagesContext = strongSelf.adMessagesContext else {
|
||||
return
|
||||
}
|
||||
for id in messageIds {
|
||||
if let message = strongSelf.messageInCurrentHistoryView(id), let adAttribute = message.adAttribute {
|
||||
adMessagesContext.markAsSeen(opaqueId: adAttribute.opaqueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.seenLiveLocationProcessingManager.process = { [weak context] messageIds in
|
||||
context?.account.viewTracker.updateSeenLiveLocationForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
@ -1096,15 +1097,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
additionalAnimatedEmojiStickers,
|
||||
customChannelDiscussionReadState,
|
||||
customThreadOutgoingReadState,
|
||||
adMessages,
|
||||
availableReactions,
|
||||
defaultReaction,
|
||||
accountPeer,
|
||||
audioTranscriptionSuggestion,
|
||||
promises,
|
||||
topicAuthorId,
|
||||
self.dynamicAdMessagesPromise.get()
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, adMessages, availableReactions, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId, dynamicAdMessages in
|
||||
self.allAdMessagesPromise.get()
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, availableReactions, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId, allAdMessages in
|
||||
let (historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, currentlyPlayingMessageIdAndType, scrollToMessageId) = promises
|
||||
let currentlyPlayingMessageId = currentlyPlayingMessageIdAndType?.0
|
||||
|
||||
@ -1265,12 +1265,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
customChannelDiscussionReadState: customChannelDiscussionReadState,
|
||||
customThreadOutgoingReadState: customThreadOutgoingReadState,
|
||||
cachedData: data.cachedData,
|
||||
adMessages: adMessages,
|
||||
dynamicAdMessages: dynamicAdMessages.0
|
||||
adMessage: allAdMessages.fixed,
|
||||
dynamicAdMessages: allAdMessages.opportunistic
|
||||
)
|
||||
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)
|
||||
let previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages, dynamicAdMessages.1))
|
||||
let previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages, allAdMessages.version))
|
||||
let previous = previousValueAndVersion?.0
|
||||
let previousSelectedMessages = previousValueAndVersion?.2
|
||||
|
||||
@ -1323,7 +1323,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
var disableAnimations = false
|
||||
var forceSynchronous = false
|
||||
|
||||
if let previousValueAndVersion = previousValueAndVersion, dynamicAdMessages.1 != previousValueAndVersion.3 {
|
||||
if let previousValueAndVersion = previousValueAndVersion, allAdMessages.version != previousValueAndVersion.3 {
|
||||
reason = ChatHistoryViewTransitionReason.Reload
|
||||
disableAnimations = true
|
||||
forceSynchronous = true
|
||||
@ -1688,6 +1688,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.preloadAdPeerDisposable.dispose()
|
||||
self.refreshDisplayedItemRangeTimer?.invalidate()
|
||||
self.genericReactionEffectDisposable?.dispose()
|
||||
self.adMessagesDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func attemptReadingReactions() {
|
||||
@ -1895,7 +1896,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
let initialMessage = self.pendingDynamicAdMessages.removeFirst()
|
||||
let message = Message(
|
||||
stableId: UInt32.max - 1 - UInt32(self.nextPendingDynamicMessageId),
|
||||
stableVersion: 1,
|
||||
stableVersion: initialMessage.stableVersion,
|
||||
id: MessageId(peerId: initialMessage.id.peerId, namespace: initialMessage.id.namespace, id: self.nextPendingDynamicMessageId),
|
||||
globallyUniqueId: nil,
|
||||
groupingKey: nil,
|
||||
@ -1908,7 +1909,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
localTags: initialMessage.localTags,
|
||||
forwardInfo: initialMessage.forwardInfo,
|
||||
author: initialMessage.author,
|
||||
text: initialMessage.text,
|
||||
text: /*"\(initialMessage.adAttribute!.opaqueId.hashValue)" + */initialMessage.text,
|
||||
attributes: initialMessage.attributes,
|
||||
media: initialMessage.media,
|
||||
peers: initialMessage.peers,
|
||||
@ -1919,12 +1920,26 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
)
|
||||
self.nextPendingDynamicMessageId += 1
|
||||
|
||||
var dynamicAdMessages = self.dynamicAdMessages
|
||||
dynamicAdMessages.0.append(message)
|
||||
dynamicAdMessages.1 += 1
|
||||
self.dynamicAdMessages = dynamicAdMessages
|
||||
var allAdMessages = self.allAdMessages
|
||||
if allAdMessages.fixed?.adAttribute?.opaqueId == message.adAttribute?.opaqueId {
|
||||
allAdMessages.fixed = self.pendingDynamicAdMessages.first?.withUpdatedStableVersion(stableVersion: UInt32(self.nextPendingDynamicMessageId))
|
||||
}
|
||||
allAdMessages.opportunistic.append(message)
|
||||
allAdMessages.version += 1
|
||||
self.allAdMessages = allAdMessages
|
||||
}
|
||||
}
|
||||
//TODO:loc mark all ads as seen
|
||||
}
|
||||
|
||||
func markAdAsSeen(opaqueId: Data) {
|
||||
for i in 0 ..< self.pendingDynamicAdMessages.count {
|
||||
if let pendingAttribute = self.pendingDynamicAdMessages[i].adAttribute, pendingAttribute.opaqueId == opaqueId {
|
||||
self.pendingDynamicAdMessages.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
self.adMessagesContext?.markAsSeen(opaqueId: opaqueId)
|
||||
}
|
||||
|
||||
private func processDisplayedItemRangeChanged(displayedRange: ListViewDisplayedItemRange, transactionState: ChatHistoryTransactionOpaqueState) {
|
||||
@ -1952,10 +1967,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
var messageIdsWithUnseenReactions: [MessageId] = []
|
||||
var messageIdsWithInactiveExtendedMedia = Set<MessageId>()
|
||||
var downloadableResourceIds: [(messageId: MessageId, resourceId: String)] = []
|
||||
var allVisibleAnchorMessageIds: [MessageId] = []
|
||||
var allVisibleAnchorMessageIds: [(MessageId, Int)] = []
|
||||
var visibleAdOpaqueIds: [Data] = []
|
||||
|
||||
if indexRange.0 <= indexRange.1 {
|
||||
for i in (indexRange.0 ... indexRange.1) {
|
||||
let nodeIndex = historyView.filteredEntries.count - 1 - i
|
||||
|
||||
switch historyView.filteredEntries[i] {
|
||||
case let .MessageEntry(message, _, _, _, _, _):
|
||||
var hasUnconsumedMention = false
|
||||
@ -1985,6 +2003,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
contentRequiredValidation = true
|
||||
} else if let attribute = attribute as? ReactionsMessageAttribute, attribute.hasUnseen {
|
||||
hasUnseenReactions = true
|
||||
} else if let attribute = attribute as? AdMessageAttribute {
|
||||
if message.stableId != ChatHistoryListNode.fixedAdMessageStableId {
|
||||
visibleAdOpaqueIds.append(attribute.opaqueId)
|
||||
}
|
||||
}
|
||||
}
|
||||
for media in message.media {
|
||||
@ -2044,7 +2066,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
topVisibleMessageRange = ChatTopVisibleMessageRange(lowerBound: message.index, upperBound: message.index, isLast: i == historyView.filteredEntries.count - 1)
|
||||
}
|
||||
if message.id.namespace == Namespaces.Message.Cloud, self.remainingDynamicAdMessageInterval != nil {
|
||||
allVisibleAnchorMessageIds.append(message.id)
|
||||
allVisibleAnchorMessageIds.append((message.id, nodeIndex))
|
||||
}
|
||||
case let .MessageGroupEntry(_, messages, _):
|
||||
for (message, _, _, _, _) in messages {
|
||||
@ -2099,7 +2121,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
if let message = messages.first {
|
||||
if message.0.id.namespace == Namespaces.Message.Cloud, self.remainingDynamicAdMessageInterval != nil {
|
||||
allVisibleAnchorMessageIds.append(message.0.id)
|
||||
allVisibleAnchorMessageIds.append((message.0.id, nodeIndex))
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -2242,6 +2264,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
if !messageIdsWithInactiveExtendedMedia.isEmpty {
|
||||
self.extendedMediaProcessingManager.update(messageIdsWithInactiveExtendedMedia)
|
||||
}
|
||||
if !visibleAdOpaqueIds.isEmpty {
|
||||
for opaqueId in visibleAdOpaqueIds {
|
||||
self.markAdAsSeen(opaqueId: opaqueId)
|
||||
}
|
||||
}
|
||||
|
||||
self.currentEarlierPrefetchMessages = toEarlierMediaMessages
|
||||
self.currentLaterPrefetchMessages = toLaterMediaMessages
|
||||
@ -2275,15 +2302,23 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
if let visible = displayedRange.visibleRange {
|
||||
let indexRange = (historyView.filteredEntries.count - 1 - visible.lastIndex, historyView.filteredEntries.count - 1 - visible.firstIndex)
|
||||
if indexRange.0 <= indexRange.1 {
|
||||
for messageId in allVisibleAnchorMessageIds {
|
||||
for (messageId, nodeIndex) in allVisibleAnchorMessageIds {
|
||||
guard let itemNode = self.itemNodeAtIndex(nodeIndex) else {
|
||||
continue
|
||||
}
|
||||
//TODO:loc optimize eviction
|
||||
if self.seenMessageIds.insert(messageId).inserted, let remainingDynamicAdMessageIntervalValue = self.remainingDynamicAdMessageInterval {
|
||||
let pendingInterval = remainingDynamicAdMessageIntervalValue - 1
|
||||
if pendingInterval <= 0 {
|
||||
if self.seenMessageIds.insert(messageId).inserted, let remainingDynamicAdMessageIntervalValue = self.remainingDynamicAdMessageInterval, let remainingDynamicAdMessageDistanceValue = self.remainingDynamicAdMessageDistance {
|
||||
let itemHeight = itemNode.bounds.height
|
||||
|
||||
let remainingDynamicAdMessageInterval = remainingDynamicAdMessageIntervalValue - 1
|
||||
let remainingDynamicAdMessageDistance = remainingDynamicAdMessageDistanceValue - itemHeight
|
||||
if remainingDynamicAdMessageInterval <= 0 && remainingDynamicAdMessageDistance <= 0.0 {
|
||||
self.remainingDynamicAdMessageInterval = self.pendingDynamicAdMessageInterval
|
||||
self.remainingDynamicAdMessageDistance = self.bounds.height
|
||||
self.maybeInsertPendingAdMessage(historyView: historyView, toLaterRange: toLaterRange, toEarlierRange: toEarlierRange)
|
||||
} else {
|
||||
self.remainingDynamicAdMessageInterval = pendingInterval
|
||||
self.remainingDynamicAdMessageInterval = remainingDynamicAdMessageInterval
|
||||
self.remainingDynamicAdMessageDistance = remainingDynamicAdMessageDistance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,11 +93,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMess
|
||||
|
||||
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
|
||||
|
||||
if preloaded {
|
||||
if tagMask == nil && view.entries.isEmpty {
|
||||
print("")
|
||||
}
|
||||
|
||||
if preloaded {
|
||||
return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id)
|
||||
} else {
|
||||
if view.isLoading {
|
||||
@ -168,10 +164,6 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMess
|
||||
}
|
||||
}
|
||||
|
||||
if tagMask == nil && view.entries.isEmpty {
|
||||
print("")
|
||||
}
|
||||
|
||||
preloaded = true
|
||||
return .HistoryView(view: view, type: .Initial(fadeIn: fadeIn), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id)
|
||||
}
|
||||
|
@ -373,6 +373,7 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
||||
let peerId: PeerId
|
||||
let peer: Peer?
|
||||
let messageReference: MessageReference?
|
||||
let adMessageId: EngineMessage.Id?
|
||||
let effectiveTimestamp: Int32
|
||||
let presentationData: ChatPresentationData
|
||||
let context: AccountContext
|
||||
@ -382,6 +383,11 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
||||
self.peerId = peerId
|
||||
self.peer = peer
|
||||
self.messageReference = messageReference
|
||||
if message.adAttribute != nil {
|
||||
self.adMessageId = message.id
|
||||
} else {
|
||||
self.adMessageId = nil
|
||||
}
|
||||
|
||||
var effectiveTimestamp = message.timestamp
|
||||
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported) {
|
||||
@ -412,7 +418,7 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
||||
}
|
||||
|
||||
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
|
||||
return ChatMessageAvatarHeaderNode(peerId: self.peerId, peer: self.peer, messageReference: self.messageReference, presentationData: self.presentationData, context: self.context, controllerInteraction: self.controllerInteraction, synchronousLoad: synchronousLoad)
|
||||
return ChatMessageAvatarHeaderNode(peerId: self.peerId, peer: self.peer, messageReference: self.messageReference, adMessageId: self.adMessageId, presentationData: self.presentationData, context: self.context, controllerInteraction: self.controllerInteraction, synchronousLoad: synchronousLoad)
|
||||
}
|
||||
|
||||
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) {
|
||||
@ -435,6 +441,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
private let peerId: PeerId
|
||||
private let messageReference: MessageReference?
|
||||
private let peer: Peer?
|
||||
private let adMessageId: EngineMessage.Id?
|
||||
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
private let avatarNode: AvatarNode
|
||||
@ -459,10 +466,11 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
}
|
||||
}
|
||||
|
||||
init(peerId: PeerId, peer: Peer?, messageReference: MessageReference?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, synchronousLoad: Bool) {
|
||||
init(peerId: PeerId, peer: Peer?, messageReference: MessageReference?, adMessageId: EngineMessage.Id?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, synchronousLoad: Bool) {
|
||||
self.peerId = peerId
|
||||
self.peer = peer
|
||||
self.messageReference = messageReference
|
||||
self.adMessageId = adMessageId
|
||||
self.presentationData = presentationData
|
||||
self.context = context
|
||||
self.controllerInteraction = controllerInteraction
|
||||
@ -636,10 +644,14 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
if self.peerId.namespace == Namespaces.Peer.Empty, case let .message(_, id, _, _, _) = self.messageReference?.content {
|
||||
self.controllerInteraction.displayMessageTooltip(id, self.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, self.avatarNode.frame)
|
||||
} else if let peer = self.peer {
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
self.controllerInteraction.openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: nil, peekData: nil), self.messageReference, false)
|
||||
if let adMessageId = self.adMessageId {
|
||||
self.controllerInteraction.activateAdAction(adMessageId)
|
||||
} else {
|
||||
self.controllerInteraction.openPeer(EnginePeer(peer), .info, self.messageReference, false)
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
self.controllerInteraction.openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: nil, peekData: nil), self.messageReference, false)
|
||||
} else {
|
||||
self.controllerInteraction.openPeer(EnginePeer(peer), .info, self.messageReference, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,28 +63,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
self.contentNode.activateAction = { [weak self] in
|
||||
if let strongSelf = self, let item = strongSelf.item {
|
||||
if let adAttribute = item.message.adAttribute {
|
||||
switch adAttribute.target {
|
||||
case let .peer(id, messageId, startParam):
|
||||
let navigationData: ChatControllerInteractionNavigateToPeer
|
||||
if let bot = item.message.author as? TelegramUser, bot.botInfo != nil, let startParam = startParam {
|
||||
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
|
||||
} else {
|
||||
var subject: ChatControllerSubject?
|
||||
if let messageId = messageId {
|
||||
subject = .message(id: .id(messageId), highlight: true, timecode: nil)
|
||||
}
|
||||
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
|
||||
}
|
||||
let _ = (item.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
if let peer = peer {
|
||||
item.controllerInteraction.openPeer(peer, navigationData, nil, false)
|
||||
}
|
||||
})
|
||||
case let .join(_, joinHash):
|
||||
item.controllerInteraction.openJoinLink(joinHash)
|
||||
}
|
||||
if let _ = item.message.adAttribute {
|
||||
item.controllerInteraction.activateAdAction(item.message.id)
|
||||
} else {
|
||||
var webPageContent: TelegramMediaWebpageLoadedContent?
|
||||
for media in item.message.media {
|
||||
|
@ -540,6 +540,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _, _, _ in
|
||||
}, activateAdAction: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -161,6 +161,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _, _, _ in
|
||||
}, activateAdAction: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -154,6 +154,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _, _, _ in
|
||||
}, activateAdAction: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -2599,6 +2599,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _, _, _ in
|
||||
}, activateAdAction: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -1348,6 +1348,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _, _, _ in
|
||||
}, activateAdAction: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -626,7 +626,7 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
|
||||
}
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> interface = strongSelf->_interface;
|
||||
|
||||
if (false && requestClone) {
|
||||
/*if (false && requestClone) {
|
||||
VideoSampleBufferView *remoteRenderer = [[VideoSampleBufferView alloc] initWithFrame:CGRectZero];
|
||||
remoteRenderer.videoContentMode = UIViewContentModeScaleAspectFill;
|
||||
|
||||
@ -643,7 +643,7 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
|
||||
}
|
||||
|
||||
completion(remoteRenderer, cloneRenderer);
|
||||
} else if ([VideoMetalView isSupported]) {
|
||||
} else */if ([VideoMetalView isSupported]) {
|
||||
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectZero];
|
||||
remoteRenderer.videoContentMode = UIViewContentModeScaleAspectFill;
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c8f6a173253e88fc77ef4ceece919a786023108e
|
||||
Subproject commit 07b225568fb596ba44d472c3fa413da2f8bd3f2e
|
Loading…
x
Reference in New Issue
Block a user