Add extended media polling

This commit is contained in:
Ilya Laktyushin 2022-09-01 14:25:48 +02:00
parent 39374476bb
commit 95ceb995d0
4 changed files with 101 additions and 27 deletions

View File

@ -303,6 +303,10 @@ public final class AccountViewTracker {
private var nextSeenLiveLocationDisposableId: Int32 = 0 private var nextSeenLiveLocationDisposableId: Int32 = 0
private var seenLiveLocationDisposables = DisposableDict<Int32>() private var seenLiveLocationDisposables = DisposableDict<Int32>()
private var updatedExtendedMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:]
private var nextUpdatedExtendedMediaDisposableId: Int32 = 0
private var updatedExtendedMediaDisposables = DisposableDict<Int32>()
private var updatedUnsupportedMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:] private var updatedUnsupportedMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:]
private var refreshSecretChatMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:] private var refreshSecretChatMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:]
private var nextUpdatedUnsupportedMediaDisposableId: Int32 = 0 private var nextUpdatedUnsupportedMediaDisposableId: Int32 = 0
@ -966,6 +970,59 @@ public final class AccountViewTracker {
} }
} }
public func updatedExtendedMediaForMessageIds(messageIds: Set<MessageId>) {
self.queue.async {
var addedMessageIds: [MessageId] = []
let timestamp = Int32(CFAbsoluteTimeGetCurrent())
for messageId in messageIds {
let messageTimestamp = self.updatedExtendedMediaMessageIdsAndTimestamps[messageId]
if messageTimestamp == nil || messageTimestamp! < timestamp - 30 {
self.updatedExtendedMediaMessageIdsAndTimestamps[messageId] = timestamp
addedMessageIds.append(messageId)
}
}
if !addedMessageIds.isEmpty {
for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(addedMessageIds)) {
let disposableId = self.nextUpdatedExtendedMediaDisposableId
self.nextUpdatedExtendedMediaDisposableId += 1
if let account = self.account {
let signal = account.postbox.transaction { transaction -> Peer? in
if let peer = transaction.getPeer(peerId) {
return peer
} else {
return nil
}
}
|> mapToSignal { peer -> Signal<Void, NoError> in
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
return .complete()
}
return account.network.request(Api.functions.messages.getExtendedMedia(peer: inputPeer, id: messageIds.map { $0.id }))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
}
|> mapToSignal { updates -> Signal<Void, NoError> in
if let updates = updates {
account.stateManager.addUpdates(updates)
}
return .complete()
}
}
|> afterDisposed { [weak self] in
self?.queue.async {
self?.updatedExtendedMediaDisposables.set(nil, forKey: disposableId)
}
}
self.updatedExtendedMediaDisposables.set(signal.start(), forKey: disposableId)
}
}
}
}
}
public func updateUnsupportedMediaForMessageIds(messageIds: Set<MessageId>) { public func updateUnsupportedMediaForMessageIds(messageIds: Set<MessageId>) {
self.queue.async { self.queue.async {
var addedMessageIds: [MessageId] = [] var addedMessageIds: [MessageId] = []

View File

@ -489,6 +489,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private let refreshMediaProcessingManager = ChatMessageThrottledProcessingManager() private let refreshMediaProcessingManager = ChatMessageThrottledProcessingManager()
private let messageMentionProcessingManager = ChatMessageThrottledProcessingManager(delay: 0.2) private let messageMentionProcessingManager = ChatMessageThrottledProcessingManager(delay: 0.2)
private let unseenReactionsProcessingManager = ChatMessageThrottledProcessingManager(delay: 0.2, submitInterval: 0.0) private let unseenReactionsProcessingManager = ChatMessageThrottledProcessingManager(delay: 0.2, submitInterval: 0.0)
private let extendedMediaProcessingManager = ChatMessageVisibleThrottledProcessingManager(interval: 5.0)
let prefetchManager: InChatPrefetchManager let prefetchManager: InChatPrefetchManager
private var currentEarlierPrefetchMessages: [(Message, Media)] = [] private var currentEarlierPrefetchMessages: [(Message, Media)] = []
private var currentLaterPrefetchMessages: [(Message, Media)] = [] private var currentLaterPrefetchMessages: [(Message, Media)] = []
@ -733,6 +735,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} }
} }
self.extendedMediaProcessingManager.process = { [weak self] messageIds in
guard let strongSelf = self else {
return
}
strongSelf.context.account.viewTracker.updatedExtendedMediaForMessageIds(messageIds: messageIds)
}
self.preloadPages = false self.preloadPages = false
switch self.mode { switch self.mode {
case .bubbles: case .bubbles:
@ -1747,6 +1756,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
var messageIdsWithRefreshMedia: [MessageId] = [] var messageIdsWithRefreshMedia: [MessageId] = []
var messageIdsWithUnseenPersonalMention: [MessageId] = [] var messageIdsWithUnseenPersonalMention: [MessageId] = []
var messageIdsWithUnseenReactions: [MessageId] = [] var messageIdsWithUnseenReactions: [MessageId] = []
var messageIdsWithInactiveExtendedMedia = Set<MessageId>()
var downloadableResourceIds: [(messageId: MessageId, resourceId: String)] = [] var downloadableResourceIds: [(messageId: MessageId, resourceId: String)] = []
if indexRange.0 <= indexRange.1 { if indexRange.0 <= indexRange.1 {
@ -1813,6 +1823,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if let representation = image.representations.last { if let representation = image.representations.last {
downloadableResourceIds.append((message.id, representation.resource.id.stringRepresentation)) downloadableResourceIds.append((message.id, representation.resource.id.stringRepresentation))
} }
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case .preview = extendedMedia {
messageIdsWithInactiveExtendedMedia.insert(message.id)
} }
} }
if contentRequiredValidation { if contentRequiredValidation {
@ -2024,6 +2036,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if !downloadableResourceIds.isEmpty { if !downloadableResourceIds.isEmpty {
let _ = markRecentDownloadItemsAsSeen(postbox: self.context.account.postbox, items: downloadableResourceIds).start() let _ = markRecentDownloadItemsAsSeen(postbox: self.context.account.postbox, items: downloadableResourceIds).start()
} }
if !messageIdsWithInactiveExtendedMedia.isEmpty {
self.extendedMediaProcessingManager.update(messageIdsWithInactiveExtendedMedia)
}
self.currentEarlierPrefetchMessages = toEarlierMediaMessages self.currentEarlierPrefetchMessages = toEarlierMediaMessages
self.currentLaterPrefetchMessages = toLaterMediaMessages self.currentLaterPrefetchMessages = toLaterMediaMessages

View File

@ -90,7 +90,7 @@ private class ExtendedMediaOverlayNode: ASDisplayNode {
self.blurNode = NavigationBackgroundNode(color: .clear) self.blurNode = NavigationBackgroundNode(color: .clear)
self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.3) self.highlightedBackgroundNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.2)
self.highlightedBackgroundNode.alpha = 0.0 self.highlightedBackgroundNode.alpha = 0.0
self.iconNode = ASImageNode() self.iconNode = ASImageNode()
@ -150,7 +150,7 @@ private class ExtendedMediaOverlayNode: ASDisplayNode {
self.highlightedBackgroundNode.frame = CGRect(origin: .zero, size: contentSize) self.highlightedBackgroundNode.frame = CGRect(origin: .zero, size: contentSize)
self.blurNode.frame = self.highlightedBackgroundNode.frame self.blurNode.frame = self.highlightedBackgroundNode.frame
self.blurNode.update(size: self.blurNode.frame.size, transition: .immediate) self.blurNode.update(size: self.blurNode.frame.size, transition: .immediate)
self.blurNode.updateColor(color: UIColor(rgb: 0xffffff, alpha: 0.2), enableBlur: true, transition: .immediate) self.blurNode.updateColor(color: UIColor(rgb: 0x000000, alpha: 0.5), enableBlur: true, transition: .immediate)
self.iconNode.frame = CGRect(origin: CGPoint(x: self.buttonNode.frame.minX + padding, y: self.buttonNode.frame.minY + floorToScreenPixels((contentSize.height - iconSize.height) / 2.0) + 1.0), size: iconSize) self.iconNode.frame = CGRect(origin: CGPoint(x: self.buttonNode.frame.minX + padding, y: self.buttonNode.frame.minY + floorToScreenPixels((contentSize.height - iconSize.height) / 2.0) + 1.0), size: iconSize)
self.textNode.frame = CGRect(origin: CGPoint(x: self.iconNode.frame.maxX + spacing, y: self.buttonNode.frame.minY + floorToScreenPixels((contentSize.height - textSize.height) / 2.0)), size: textSize) self.textNode.frame = CGRect(origin: CGPoint(x: self.iconNode.frame.maxX + spacing, y: self.buttonNode.frame.minY + floorToScreenPixels((contentSize.height - textSize.height) / 2.0)), size: textSize)
@ -1673,14 +1673,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if self.badgeNode == nil { if self.badgeNode == nil {
let badgeNode = ChatMessageInteractiveMediaBadge() let badgeNode = ChatMessageInteractiveMediaBadge()
let incoming: Bool var inset: CGFloat = 6.0
if let context = self.context, let message = self.message { if let corners = self.currentImageArguments?.corners, case .Tail = corners.bottomLeft {
incoming = message.effectivelyIncoming(context.account.peerId) inset = 10.0
} else {
incoming = false
} }
badgeNode.frame = CGRect(origin: CGPoint(x: incoming ? 10.0 : 6.0, y: 6.0), size: CGSize(width: radialStatusSize, height: radialStatusSize)) badgeNode.frame = CGRect(origin: CGPoint(x: inset, y: 6.0), size: CGSize(width: radialStatusSize, height: radialStatusSize))
badgeNode.pressed = { [weak self] in badgeNode.pressed = { [weak self] in
guard let strongSelf = self, let fetchStatus = strongSelf.fetchStatus else { guard let strongSelf = self, let fetchStatus = strongSelf.fetchStatus else {
return return

View File

@ -78,16 +78,33 @@ final class ChatMessageThrottledProcessingManager {
final class ChatMessageVisibleThrottledProcessingManager { final class ChatMessageVisibleThrottledProcessingManager {
private let queue = Queue() private let queue = Queue()
private let delay: Double private let interval: Double
private var currentIds = Set<MessageId>() private var currentIds = Set<MessageId>()
var process: ((Set<MessageId>) -> Void)? var process: ((Set<MessageId>) -> Void)?
private var timer: SwiftSignalKit.Timer? private let timer: SwiftSignalKit.Timer
init(delay: Double = 1.0) { init(interval: Double = 5.0) {
self.delay = delay self.interval = interval
var completionImpl: (() -> Void)?
let timer = SwiftSignalKit.Timer(timeout: self.interval, repeat: true, completion: {
completionImpl?()
}, queue: self.queue)
self.timer = timer
timer.start()
completionImpl = { [weak self] in
if let strongSelf = self, !strongSelf.currentIds.isEmpty {
strongSelf.process?(strongSelf.currentIds)
}
}
}
deinit {
self.timer.invalidate()
} }
func setProcess(process: @escaping (Set<MessageId>) -> Void) { func setProcess(process: @escaping (Set<MessageId>) -> Void) {
@ -100,21 +117,8 @@ final class ChatMessageVisibleThrottledProcessingManager {
self.queue.async { self.queue.async {
if self.currentIds != ids { if self.currentIds != ids {
self.currentIds = ids self.currentIds = ids
if self.timer == nil { if !self.currentIds.isEmpty {
var completionImpl: (() -> Void)? self.process?(self.currentIds)
let timer = SwiftSignalKit.Timer(timeout: self.delay, repeat: false, completion: {
completionImpl?()
}, queue: self.queue)
completionImpl = { [weak self, weak timer] in
if let strongSelf = self {
if let timer = timer, strongSelf.timer === timer {
strongSelf.timer = nil
}
strongSelf.process?(strongSelf.currentIds)
}
}
self.timer = timer
timer.start()
} }
} }
} }