diff --git a/submodules/Postbox/Sources/Message.swift b/submodules/Postbox/Sources/Message.swift index bed76188af..90de067a6b 100644 --- a/submodules/Postbox/Sources/Message.swift +++ b/submodules/Postbox/Sources/Message.swift @@ -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) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a94316ab21..bb1d8f7c5a 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -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 diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index 09c0f070a1..26fed4917d 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -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 diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index 74cba9b745..e8845b4aa9 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -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 { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 0ef1029782..be1dcf86e8 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -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 @@ -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() 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() 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 } } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift index c227ba7d60..2fbc11de14 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift @@ -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) } diff --git a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift index 78b6e54388..f64cbc03a9 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift @@ -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) + } } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift index 1235d0631f..9556e8590c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -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 { diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 9571a1fa18..ab3dbb4d04 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -540,6 +540,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, openLargeEmojiInfo: { _, _, _ in }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in + }, activateAdAction: { _ in }, requestMessageUpdate: { _, _ in }, cancelInteractiveKeyboardGestures: { }, dismissTextInput: { diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 471c914f81..c00caf0884 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -161,6 +161,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, openLargeEmojiInfo: { _, _, _ in }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in + }, activateAdAction: { _ in }, requestMessageUpdate: { _, _ in }, cancelInteractiveKeyboardGestures: { }, dismissTextInput: { diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 9b99fb6e54..2e7429f1ef 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -154,6 +154,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, openLargeEmojiInfo: { _, _, _ in }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in + }, activateAdAction: { _ in }, requestMessageUpdate: { _, _ in }, cancelInteractiveKeyboardGestures: { }, dismissTextInput: { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index b99bca27ad..0bcda7515a 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2599,6 +2599,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, openLargeEmojiInfo: { _, _, _ in }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in + }, activateAdAction: { _ in }, requestMessageUpdate: { _, _ in }, cancelInteractiveKeyboardGestures: { }, dismissTextInput: { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index b195d0458d..0a7e5a3c94 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1348,6 +1348,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, openLargeEmojiInfo: { _, _, _ in }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in + }, activateAdAction: { _ in }, requestMessageUpdate: { _, _ in }, cancelInteractiveKeyboardGestures: { }, dismissTextInput: { diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 1c0cbe2633..32c1ddb7d2 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -626,7 +626,7 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls: } std::shared_ptr 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; diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index c8f6a17325..07b225568f 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit c8f6a173253e88fc77ef4ceece919a786023108e +Subproject commit 07b225568fb596ba44d472c3fa413da2f8bd3f2e