Media preload fixes

This commit is contained in:
Peter 2019-03-02 00:03:06 +04:00
parent df83998c74
commit 4a9e6d20db
8 changed files with 358 additions and 49 deletions

View File

@ -323,6 +323,7 @@
D05D8B742195CD890064586F /* SetupTwoStepVerificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B732195CD890064586F /* SetupTwoStepVerificationController.swift */; };
D05D8B762195CD930064586F /* SetupTwoStepVerificationControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B752195CD930064586F /* SetupTwoStepVerificationControllerNode.swift */; };
D05D8B782195E0050064586F /* SetupTwoStepVerificationContentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B772195E0050064586F /* SetupTwoStepVerificationContentNode.swift */; };
D06350AE2229A7F800FA2B32 /* InChatPrefetchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06350AD2229A7F800FA2B32 /* InChatPrefetchManager.swift */; };
D0642EFC1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */; };
D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D064EF861F69A06F00AC0398 /* MessageContentKind.swift */; };
D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */; };
@ -1701,6 +1702,7 @@
D0613FC71E5F8AB100202CDB /* ChannelInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelInfoController.swift; sourceTree = "<group>"; };
D0613FCC1E60482300202CDB /* ChannelMembersController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMembersController.swift; sourceTree = "<group>"; };
D0613FD41E6064D200202CDB /* ConvertToSupergroupController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertToSupergroupController.swift; sourceTree = "<group>"; };
D06350AD2229A7F800FA2B32 /* InChatPrefetchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InChatPrefetchManager.swift; sourceTree = "<group>"; };
D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryNavigationButtons.swift; sourceTree = "<group>"; };
D064EF861F69A06F00AC0398 /* MessageContentKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContentKind.swift; sourceTree = "<group>"; };
D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoStepVerificationEmptyItem.swift; sourceTree = "<group>"; };
@ -4521,6 +4523,7 @@
D0F69E441D6B8B850046BCD6 /* History Navigation */,
D044A0FA20BDC40C00326FAC /* CachedChannelAdmins.swift */,
D01848E721A03BDA00B6DEBD /* ChatSearchState.swift */,
D06350AD2229A7F800FA2B32 /* InChatPrefetchManager.swift */,
);
name = Chat;
sourceTree = "<group>";
@ -5816,6 +5819,7 @@
D0477D1B1F617E5800412B44 /* UniversalVideoNode.swift in Sources */,
D0E9BA081F0446A300F079A4 /* BotCheckoutPaymentShippingOptionSheetController.swift in Sources */,
D0EC6DDC1EB9F58900EBF1C3 /* ChatTextInputPanelNode.swift in Sources */,
D06350AE2229A7F800FA2B32 /* InChatPrefetchManager.swift in Sources */,
D0EB41F51F30D26A00838FE6 /* LegacySuggestionContext.swift in Sources */,
D0EC6DDD1EB9F58900EBF1C3 /* ChatTextInputMediaRecordingButton.swift in Sources */,
D0F0AAE61EC21B68005EE2A5 /* CallControllerButton.swift in Sources */,

View File

@ -1544,7 +1544,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
strongSelf.automaticMediaDownloadSettings = downloadSettings
strongSelf.controllerInteraction?.automaticMediaDownloadSettings = downloadSettings
if strongSelf.isNodeLoaded {
strongSelf.chatDisplayNode.updateAutomaticMediaDownloadSettings()
strongSelf.chatDisplayNode.updateAutomaticMediaDownloadSettings(downloadSettings)
}
}
})
@ -1964,7 +1964,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
stationaryItemRange = (maxInsertedItem + 1, Int.max)
}
mappedTransition = (ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: deleteItems, insertItems: insertItems, updateItems: transition.updateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, animateIn: false), updateSizeAndInsets)
mappedTransition = (ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: deleteItems, insertItems: insertItems, updateItems: transition.updateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, peerType: transition.peerType, networkType: transition.networkType, animateIn: false), updateSizeAndInsets)
})
if let mappedTransition = mappedTransition {

View File

@ -1474,12 +1474,13 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
func updateAutomaticMediaDownloadSettings() {
func updateAutomaticMediaDownloadSettings(_ settings: MediaAutoDownloadSettings) {
self.historyNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView {
itemNode.updateAutomaticMediaDownloadSettings()
}
}
self.historyNode.prefetchManager.updateAutoDownloadSettings(settings)
}
func playFirstMediaWithSound() {

View File

@ -118,6 +118,8 @@ struct ChatHistoryListViewTransition {
let cachedDataMessages: [MessageId: Message]?
let readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?
let scrolledToIndex: MessageHistoryAnchorIndex?
let peerType: MediaAutoDownloadPeerType
let networkType: MediaAutoDownloadNetworkType
let animateIn: Bool
}
@ -252,7 +254,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
}
private func mappedChatHistoryViewListTransition(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, transition: ChatHistoryViewTransition) -> ChatHistoryListViewTransition {
return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, animateIn: transition.animateIn)
return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, animateIn: transition.animateIn)
}
private final class ChatHistoryTransactionOpaqueState {
@ -363,6 +365,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private let messageProcessingManager = ChatMessageThrottledProcessingManager()
private let unsupportedMessageProcessingManager = ChatMessageThrottledProcessingManager()
private let messageMentionProcessingManager = ChatMessageThrottledProcessingManager(delay: 0.2)
let prefetchManager: InChatPrefetchManager
private var currentEarlierPrefetchMessages: [(Message, Media)] = []
private var currentLaterPrefetchMessages: [(Message, Media)] = []
private var currentPrefetchDirectionIsToLater: Bool = true
private var maxVisibleMessageIndexReported: MessageIndex?
var maxVisibleMessageIndexUpdated: ((MessageIndex) -> Void)?
@ -416,6 +422,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.currentPresentationData.theme, wallpaper: self.currentPresentationData.chatWallpaper), fontSize: self.currentPresentationData.fontSize, strings: self.currentPresentationData.strings, dateTimeFormat: self.currentPresentationData.dateTimeFormat, nameDisplayOrder: self.currentPresentationData.nameDisplayOrder, disableAnimations: self.currentPresentationData.disableAnimations))
self.prefetchManager = InChatPrefetchManager(context: context)
super.init()
self.dynamicBounceEnabled = !self.currentPresentationData.disableAnimations
@ -632,6 +640,21 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Initial(count: 60), id: 0))
}
self.generalScrollDirectionUpdated = { [weak self] direction in
guard let strongSelf = self else {
return
}
let prefetchDirectionIsToLater = direction == .up
if strongSelf.currentPrefetchDirectionIsToLater != prefetchDirectionIsToLater {
strongSelf.currentPrefetchDirectionIsToLater = prefetchDirectionIsToLater
if strongSelf.currentPrefetchDirectionIsToLater {
strongSelf.prefetchManager.updateMessages(strongSelf.currentLaterPrefetchMessages, directionIsToLater: strongSelf.currentPrefetchDirectionIsToLater)
} else {
strongSelf.prefetchManager.updateMessages(strongSelf.currentEarlierPrefetchMessages, directionIsToLater: strongSelf.currentPrefetchDirectionIsToLater)
}
}
}
self.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
if let strongSelf = self {
if let historyView = (opaqueTransactionState as? ChatHistoryTransactionOpaqueState)?.historyView {
@ -639,13 +662,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let indexRange = (historyView.filteredEntries.count - 1 - visible.lastIndex, historyView.filteredEntries.count - 1 - visible.firstIndex)
let readIndexRange = (0, historyView.filteredEntries.count - 1 - visible.firstIndex)
/*if !visible.firstIndexFullyVisible {
readIndexRange.1 -= 1
}*/
let toEarlierRange = (0, historyView.filteredEntries.count - 1 - visible.firstIndex - 1)
let toLaterRange = (historyView.filteredEntries.count - 1 - visible.lastIndex + 1, historyView.filteredEntries.count - 1)
var messageIdsWithViewCount: [MessageId] = []
var messageIdsWithUnsupportedMedia: [MessageId] = []
var messageIdsWithUnseenPersonalMention: [MessageId] = []
var messagesWithPreloadableMediaToEarlier: [(Message, Media)] = []
var messagesWithPreloadableMediaToLater: [(Message, Media)] = []
for i in (indexRange.0 ... indexRange.1) {
switch historyView.filteredEntries[i] {
case let .MessageEntry(message, _, _, _, _, _):
@ -704,6 +730,69 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
}
}
func addMediaToPrefetch(_ message: Message, _ media: Media, _ messages: inout [(Message, Media)]) -> Bool {
if media is TelegramMediaImage || media is TelegramMediaFile {
messages.append((message, media))
}
if messages.count >= 3 {
return false
} else {
return true
}
}
var toEarlierMediaMessages: [(Message, Media)] = []
if toEarlierRange.0 <= toEarlierRange.1 {
outer: for i in (toEarlierRange.0 ... toEarlierRange.1).reversed() {
switch historyView.filteredEntries[i] {
case let .MessageEntry(message, _, _, _, _, _):
for media in message.media {
if !addMediaToPrefetch(message, media, &toEarlierMediaMessages) {
break outer
}
}
case let .MessageGroupEntry(_, messages, _):
for (message, _, _, _) in messages {
var stop = false
for media in message.media {
if !addMediaToPrefetch(message, media, &toEarlierMediaMessages) {
stop = true
}
}
if stop {
break outer
}
}
default:
break
}
}
}
var toLaterMediaMessages: [(Message, Media)] = []
if toLaterRange.0 <= toLaterRange.1 {
outer: for i in (toLaterRange.0 ... toLaterRange.1) {
switch historyView.filteredEntries[i] {
case let .MessageEntry(message, _, _, _, _, _):
for media in message.media {
if !addMediaToPrefetch(message, media, &toLaterMediaMessages) {
break outer
}
}
case let .MessageGroupEntry(_, messages, _):
for (message, _, _, _) in messages {
for media in message.media {
if !addMediaToPrefetch(message, media, &toLaterMediaMessages) {
break outer
}
}
}
default:
break
}
}
}
if !messageIdsWithViewCount.isEmpty {
strongSelf.messageProcessingManager.add(messageIdsWithViewCount)
}
@ -714,6 +803,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
strongSelf.messageMentionProcessingManager.add(messageIdsWithUnseenPersonalMention)
}
strongSelf.currentEarlierPrefetchMessages = toEarlierMediaMessages
strongSelf.currentLaterPrefetchMessages = toLaterMediaMessages
if strongSelf.currentPrefetchDirectionIsToLater {
strongSelf.prefetchManager.updateMessages(toLaterMediaMessages, directionIsToLater: strongSelf.currentPrefetchDirectionIsToLater)
} else {
strongSelf.prefetchManager.updateMessages(toEarlierMediaMessages, directionIsToLater: strongSelf.currentPrefetchDirectionIsToLater)
}
if readIndexRange.0 <= readIndexRange.1 {
let (maxIncomingIndex, maxOverallIndex) = maxMessageIndexForEntries(historyView, indexRange: readIndexRange)
@ -978,6 +1075,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
preconditionFailure()
}
strongSelf.prefetchManager.updateOptions(InChatPrefetchOptions(networkType: transition.networkType, peerType: transition.peerType))
if !strongSelf.didSetInitialData {
strongSelf.didSetInitialData = true
strongSelf._initialData.set(.single(ChatHistoryCombinedInitialData(initialData: transition.initialData, buttonKeyboardMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData)))

View File

@ -27,9 +27,15 @@ private struct FetchManagerLocationEntryId: Hashable {
}
}
enum FetchManagerForegroundDirection {
case toEarlier
case toLater
}
enum FetchManagerPriority: Comparable {
case userInitiated
case backgroundPrefetch(MessageIndex)
case foregroundPrefetch(direction: FetchManagerForegroundDirection, localOrder: MessageIndex)
case backgroundPrefetch(locationOrder: HistoryPreloadIndex, localOrder: MessageIndex)
static func <(lhs: FetchManagerPriority, rhs: FetchManagerPriority) -> Bool {
switch lhs {
@ -37,15 +43,44 @@ enum FetchManagerPriority: Comparable {
switch rhs {
case .userInitiated:
return false
case .foregroundPrefetch:
return true
case .backgroundPrefetch:
return true
}
case let .backgroundPrefetch(lhsIndex):
case let .foregroundPrefetch(lhsDirection, lhsLocalOrder):
switch rhs {
case .userInitiated:
return false
case let .backgroundPrefetch(rhsIndex):
return lhsIndex > rhsIndex
case let .foregroundPrefetch(rhsDirection, rhsLocalOrder):
if lhsDirection == rhsDirection {
switch lhsDirection {
case .toEarlier:
return lhsLocalOrder > rhsLocalOrder
case .toLater:
return lhsLocalOrder < rhsLocalOrder
}
} else {
if lhsDirection == .toEarlier {
return true
} else {
return false
}
}
case .backgroundPrefetch:
return true
}
case let .backgroundPrefetch(lhsLocationOrder, lhsLocalOrder):
switch rhs {
case .userInitiated:
return false
case .foregroundPrefetch:
return false
case let .backgroundPrefetch(rhsLocationOrder, rhsLocalOrder):
if lhsLocationOrder != rhsLocationOrder {
return lhsLocationOrder < rhsLocationOrder
}
return lhsLocalOrder > rhsLocalOrder
}
}
}
@ -231,6 +266,7 @@ private final class FetchManagerCategoryContext {
}
parsedRanges = resultRanges
}
activeContext.disposable?.dispose()
activeContext.disposable = (fetchedMediaResource(postbox: self.postbox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if let storeManager = storeManager, let mediaReference = entry.mediaReference, case .remote = type, let peerType = entry.storeToDownloadsPeerType {
@ -307,14 +343,22 @@ private final class FetchManagerCategoryContext {
self.topEntryIdAndPriority = topEntryIdAndPriority
}
if let topEntryId = self.topEntryIdAndPriority?.0, self.activeContexts[topEntryId] == nil {
if let topEntryId = self.topEntryIdAndPriority?.0 {
if let entry = self.entries[topEntryId] {
let activeContext = FetchManagerActiveContext(userInitiated: entry.userInitiated)
let ranges = entry.combinedRanges
activeContext.ranges = ranges
let parsedRanges: [(Range<Int>, MediaBoxFetchPriority)]?
if ranges.count == 1 && ranges.min() == 0 && ranges.max() == Int(Int32.max) {
var count = 0
var isCompleteRange = false
for range in ranges.rangeView {
count += 1
if range.lowerBound == 0 && range.upperBound == Int(Int32.max) {
isCompleteRange = true
}
}
if count == 1 && isCompleteRange {
parsedRanges = nil
} else {
var resultRanges: [(Range<Int>, MediaBoxFetchPriority)] = []
@ -324,26 +368,45 @@ private final class FetchManagerCategoryContext {
parsedRanges = resultRanges
}
self.activeContexts[topEntryId] = activeContext
let entryCompleted = self.entryCompleted
let storeManager = self.storeManager
activeContext.disposable = (fetchedMediaResource(postbox: self.postbox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if let storeManager = storeManager, let mediaReference = entry.mediaReference, case .remote = type, let peerType = entry.storeToDownloadsPeerType {
return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType)
|> introduceError(FetchResourceError.self)
|> mapToSignal { _ -> Signal<FetchResourceSourceType, FetchResourceError> in
return .complete()
}
|> then(.single(type))
}
return .single(type)
let activeContext: FetchManagerActiveContext
var restart = false
if let current = self.activeContexts[topEntryId] {
activeContext = current
restart = activeContext.ranges != ranges
} else {
activeContext = FetchManagerActiveContext(userInitiated: entry.userInitiated)
self.activeContexts[topEntryId] = activeContext
restart = true
}
|> deliverOnMainQueue).start(next: { _ in
entryCompleted(topEntryId)
if restart {
activeContext.ranges = ranges
})
return true
let entryCompleted = self.entryCompleted
let storeManager = self.storeManager
activeContext.disposable?.dispose()
if ranges.isEmpty {
} else {
activeContext.disposable = (fetchedMediaResource(postbox: self.postbox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if let storeManager = storeManager, let mediaReference = entry.mediaReference, case .remote = type, let peerType = entry.storeToDownloadsPeerType {
return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType)
|> introduceError(FetchResourceError.self)
|> mapToSignal { _ -> Signal<FetchResourceSourceType, FetchResourceError> in
return .complete()
}
|> then(.single(type))
}
return .single(type)
}
|> deliverOnMainQueue).start(next: { _ in
entryCompleted(topEntryId)
})
}
return true
} else {
return false
}
} else {
assertionFailure()
return false

View File

@ -0,0 +1,138 @@
import Foundation
import SwiftSignalKit
import Postbox
import TelegramCore
private final class PrefetchMediaContext {
let fetchDisposable = MetaDisposable()
init() {
}
}
struct InChatPrefetchOptions: Equatable {
let networkType: MediaAutoDownloadNetworkType
let peerType: MediaAutoDownloadPeerType
}
final class InChatPrefetchManager {
private let context: AccountContext
private var settings: MediaAutoDownloadSettings
private var options: InChatPrefetchOptions?
private var messages: [(Message, Media)] = []
private var directionIsToLater: Bool = true
private var contexts: [MediaId: PrefetchMediaContext] = [:]
init(context: AccountContext) {
self.context = context
self.settings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
}
func updateAutoDownloadSettings(_ settings: MediaAutoDownloadSettings) {
if self.settings != settings {
self.settings = settings
self.update()
}
}
func updateOptions(_ options: InChatPrefetchOptions) {
if self.options != options {
self.options = options
self.update()
}
}
func updateMessages(_ messages: [(Message, Media)], directionIsToLater: Bool) {
self.messages = messages
self.directionIsToLater = directionIsToLater
self.update()
}
private func update() {
guard let options = self.options else {
return
}
var validIds = Set<MediaId>()
for (message, media) in self.messages {
guard let id = media.id else {
continue
}
if validIds.contains(id) {
continue
}
var mediaResource: MediaResource?
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
if let telegramImage = media as? TelegramMediaImage {
mediaResource = largestRepresentationForPhoto(telegramImage)?.resource
if shouldDownloadMediaAutomatically(settings: self.settings, peerType: options.peerType, networkType: options.networkType, authorPeerId: nil, contactsPeerIds: [], media: telegramImage) {
automaticDownload = .full
}
} else if let telegramFile = media as? TelegramMediaFile {
mediaResource = telegramFile.resource
if shouldDownloadMediaAutomatically(settings: self.settings, peerType: options.peerType, networkType: options.networkType, authorPeerId: nil, contactsPeerIds: [], media: telegramFile) {
automaticDownload = .full
} else if shouldPredownloadMedia(settings: self.settings, peerType: options.peerType, networkType: options.networkType, media: telegramFile) {
automaticDownload = .prefetch
}
}
if case .none = automaticDownload {
continue
}
guard let resource = mediaResource else {
continue
}
validIds.insert(id)
let context: PrefetchMediaContext
if let current = self.contexts[id] {
context = current
} else {
context = PrefetchMediaContext()
self.contexts[id] = context
let priority: FetchManagerPriority = .foregroundPrefetch(direction: self.directionIsToLater ? .toLater : .toEarlier, localOrder: MessageIndex(message))
if case .full = automaticDownload {
if let image = media as? TelegramMediaImage {
context.fetchDisposable.set(messageMediaImageInteractiveFetched(fetchManager: self.context.fetchManager, messageId: message.id, messageReference: MessageReference(message), image: image, resource: resource, userInitiated: false, priority: priority, storeToDownloadsPeerType: nil).start())
} else if let _ = media as? TelegramMediaWebFile {
//strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start())
} else if let file = media as? TelegramMediaFile {
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.context.fetchManager, messageId: message.id, messageReference: MessageReference(message), file: file, userInitiated: false, priority: priority)
context.fetchDisposable.set(fetchSignal.start())
}
} else if case .prefetch = automaticDownload, message.id.peerId.namespace != Namespaces.Peer.SecretChat {
if let file = media as? TelegramMediaFile, let fileSize = file.size {
let fetchHeadRange: Range<Int> = 0 ..< 2 * 1024 * 1024
let fetchTailRange: Range<Int> = fileSize - 256 * 1024 ..< Int(Int32.max)
var ranges = IndexSet()
ranges.insert(integersIn: fetchHeadRange)
ranges.insert(integersIn: fetchTailRange)
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.context.fetchManager, messageId: message.id, messageReference: MessageReference(message), file: file, ranges: ranges, userInitiated: false, priority: priority)
context.fetchDisposable.set(fetchSignal.start())
}
}
}
}
var removeIds: [MediaId] = []
for key in self.contexts.keys {
if !validIds.contains(key) {
removeIds.append(key)
}
}
for id in removeIds {
if let context = self.contexts.removeValue(forKey: id) {
context.fetchDisposable.dispose()
}
}
}
}

View File

@ -4,11 +4,9 @@ import Postbox
import TelegramCore
private final class PrefetchMediaContext {
let media: HolesViewMedia
let fetchDisposable = MetaDisposable()
init(media: HolesViewMedia) {
self.media = media
init() {
}
}
@ -48,36 +46,39 @@ private final class PrefetchManagerImpl {
self.listDisposable?.dispose()
}
private func updateOrderedPreloadMedia(_ orderedPreloadMedia: [HolesViewMedia], automaticDownloadSettings: MediaAutoDownloadSettings, networkType: MediaAutoDownloadNetworkType) {
private func updateOrderedPreloadMedia(_ orderedPreloadMedia: [ChatHistoryPreloadMediaItem], automaticDownloadSettings: MediaAutoDownloadSettings, networkType: MediaAutoDownloadNetworkType) {
var validIds = Set<MediaId>()
for mediaItem in orderedPreloadMedia {
guard let id = mediaItem.media.id else {
guard let id = mediaItem.media.media.id else {
continue
}
if validIds.contains(id) {
continue
}
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
let peerType: MediaAutoDownloadPeerType
if mediaItem.authorIsContact {
if mediaItem.media.authorIsContact {
peerType = .contact
} else if let channel = mediaItem.peer as? TelegramChannel {
} else if let channel = mediaItem.media.peer as? TelegramChannel {
if case .group = channel.info {
peerType = .group
} else {
peerType = .channel
}
} else if mediaItem.peer is TelegramGroup {
} else if mediaItem.media.peer is TelegramGroup {
peerType = .group
} else {
peerType = .otherPrivate
}
var mediaResource: MediaResource?
if let telegramImage = mediaItem.media as? TelegramMediaImage {
if let telegramImage = mediaItem.media.media as? TelegramMediaImage {
mediaResource = largestRepresentationForPhoto(telegramImage)?.resource
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: peerType, networkType: networkType, authorPeerId: nil, contactsPeerIds: [], media: telegramImage) {
automaticDownload = .full
}
} else if let telegramFile = mediaItem.media as? TelegramMediaFile {
} else if let telegramFile = mediaItem.media.media as? TelegramMediaFile {
mediaResource = telegramFile.resource
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: peerType, networkType: networkType, authorPeerId: nil, contactsPeerIds: [], media: telegramFile) {
automaticDownload = .full
@ -98,21 +99,23 @@ private final class PrefetchManagerImpl {
if let current = self.contexts[id] {
context = current
} else {
context = PrefetchMediaContext(media: mediaItem)
context = PrefetchMediaContext()
self.contexts[id] = context
let media = mediaItem.media
let media = mediaItem.media.media
let priority: FetchManagerPriority = .backgroundPrefetch(locationOrder: mediaItem.preloadIndex, localOrder: mediaItem.media.index)
if case .full = automaticDownload {
if let image = media as? TelegramMediaImage {
context.fetchDisposable.set(messageMediaImageInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.index.id, messageReference: MessageReference(peer: mediaItem.peer, id: mediaItem.index.id, timestamp: mediaItem.index.timestamp, incoming: true, secret: false), image: image, resource: resource, userInitiated: false, priority: .backgroundPrefetch(mediaItem.index), storeToDownloadsPeerType: nil).start())
context.fetchDisposable.set(messageMediaImageInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.media.index.id, messageReference: MessageReference(peer: mediaItem.media.peer, id: mediaItem.media.index.id, timestamp: mediaItem.media.index.timestamp, incoming: true, secret: false), image: image, resource: resource, userInitiated: false, priority: priority, storeToDownloadsPeerType: nil).start())
} else if let _ = media as? TelegramMediaWebFile {
//strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start())
} else if let file = media as? TelegramMediaFile {
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.index.id, messageReference: MessageReference(peer: mediaItem.peer, id: mediaItem.index.id, timestamp: mediaItem.index.timestamp, incoming: true, secret: false), file: file, userInitiated: false, priority: .backgroundPrefetch(mediaItem.index))
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.media.index.id, messageReference: MessageReference(peer: mediaItem.media.peer, id: mediaItem.media.index.id, timestamp: mediaItem.media.index.timestamp, incoming: true, secret: false), file: file, userInitiated: false, priority: priority)
context.fetchDisposable.set(fetchSignal.start())
}
} else if case .prefetch = automaticDownload, mediaItem.peer.id.namespace != Namespaces.Peer.SecretChat {
} else if case .prefetch = automaticDownload, mediaItem.media.peer.id.namespace != Namespaces.Peer.SecretChat {
if let file = media as? TelegramMediaFile, let fileSize = file.size {
let fetchHeadRange: Range<Int> = 0 ..< 2 * 1024 * 1024
let fetchTailRange: Range<Int> = fileSize - 256 * 1024 ..< Int(Int32.max)
@ -121,7 +124,7 @@ private final class PrefetchManagerImpl {
ranges.insert(integersIn: fetchHeadRange)
ranges.insert(integersIn: fetchTailRange)
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.index.id, messageReference: MessageReference(peer: mediaItem.peer, id: mediaItem.index.id, timestamp: mediaItem.index.timestamp, incoming: true, secret: false), file: file, ranges: ranges, userInitiated: false, priority: .backgroundPrefetch(mediaItem.index))
let fetchSignal = messageMediaFileInteractiveFetched(fetchManager: self.fetchManager, messageId: mediaItem.media.index.id, messageReference: MessageReference(peer: mediaItem.media.peer, id: mediaItem.media.index.id, timestamp: mediaItem.media.index.timestamp, incoming: true, secret: false), file: file, ranges: ranges, userInitiated: false, priority: priority)
context.fetchDisposable.set(fetchSignal.start())
}
}

View File

@ -361,6 +361,7 @@ public final class SharedAccountContext {
assertionFailure()
}
self.activeAccountsValue!.accounts.append((account.id, account, accountRecord.2))
account.resetStateManagement()
hadUpdates = true
} else {
let _ = accountManager.transaction({ transaction in