mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-20 15:35:19 +00:00
Media preload fixes
This commit is contained in:
parent
df83998c74
commit
4a9e6d20db
@ -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 */,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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)))
|
||||
|
||||
@ -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
|
||||
|
||||
138
TelegramUI/InChatPrefetchManager.swift
Normal file
138
TelegramUI/InChatPrefetchManager.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user