[WIP] Modern cache

This commit is contained in:
Ali 2022-12-17 00:17:31 +04:00
parent 792e0091bc
commit 614c74b0b0
189 changed files with 1464 additions and 848 deletions

View File

@ -1142,14 +1142,20 @@ private final class NotificationServiceHandler {
var fetchMediaSignal: Signal<Data?, NoError> = .single(nil)
if let mediaAttachment = mediaAttachment {
var contentType: MediaResourceUserContentType = .other
var fetchResource: TelegramMultipartFetchableResource?
if let image = mediaAttachment as? TelegramMediaImage, let representation = largestImageRepresentation(image.representations), let resource = representation.resource as? TelegramMultipartFetchableResource {
fetchResource = resource
contentType = .image
} else if let file = mediaAttachment as? TelegramMediaFile {
if file.isSticker {
fetchResource = file.resource as? TelegramMultipartFetchableResource
contentType = .other
} else if file.isVideo {
fetchResource = file.previewRepresentations.first?.resource as? TelegramMultipartFetchableResource
contentType = .video
} else {
contentType = .file
}
}
@ -1175,6 +1181,7 @@ private final class NotificationServiceHandler {
messageId: messageId
)
},
contentType: contentType,
isRandomAccessAllowed: true
),
encryptionKey: nil,
@ -1227,6 +1234,7 @@ private final class NotificationServiceHandler {
tag: nil,
info: resourceFetchInfo(resource: resource),
location: nil,
contentType: .other,
isRandomAccessAllowed: true
),
encryptionKey: nil,

View File

@ -8512,3 +8512,7 @@ Sorry for the inconvenience.";
"GroupInfo.TitleMembers_1" = "%@ Member";
"GroupInfo.TitleMembers_any" = "%@ Members";
"PeerInfo.HideMembersLimitedParticipantCountText_1" = "Only groups with more than **%d member** can have their member list hidden.";
"PeerInfo.HideMembersLimitedParticipantCountText_any" = "Only groups with more than **%d members** can have their member list hidden.";
"PeerInfo.HideMembersLimitedRights" = "You don't have permission to change this setting.";

View File

@ -6,8 +6,8 @@ import SwiftSignalKit
import TelegramUIPreferences
import RangeSet
public func freeMediaFileInteractiveFetched(account: Account, fileReference: FileMediaReference) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource))
public func freeMediaFileInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(fileReference.media.resource))
}
public func freeMediaFileInteractiveFetched(fetchManager: FetchManager, fileReference: FileMediaReference, priority: FetchManagerPriority) -> Signal<Void, NoError> {
@ -16,8 +16,8 @@ public func freeMediaFileInteractiveFetched(fetchManager: FetchManager, fileRefe
return fetchManager.interactivelyFetched(category: fetchCategoryForFile(file), location: .chat(PeerId(0)), locationKey: .free, mediaReference: mediaReference, resourceReference: mediaReference.resourceReference(file.resource), ranges: RangeSet<Int64>(0 ..< Int64.max), statsCategory: statsCategoryForFileWithAttributes(file.attributes), elevatedPriority: false, userInitiated: false, priority: priority, storeToDownloadsPeerType: nil)
}
public func freeMediaFileResourceInteractiveFetched(account: Account, fileReference: FileMediaReference, resource: MediaResource) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource))
public func freeMediaFileResourceInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, resource: MediaResource) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(resource))
}
public func cancelFreeMediaFileInteractiveFetch(account: Account, file: TelegramMediaFile) {

View File

@ -421,7 +421,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return UIView()
}
return EmojiTextAttachmentView(context: context, emoji: emoji, file: emoji.file, cache: strongSelf.animationCache, renderer: strongSelf.animationRenderer, placeholderColor: presentationInterfaceState.theme.chat.inputPanel.inputTextColor.withAlphaComponent(0.12), pointSize: CGSize(width: 24.0, height: 24.0))
return EmojiTextAttachmentView(context: context, userLocation: .other, emoji: emoji, file: emoji.file, cache: strongSelf.animationCache, renderer: strongSelf.animationRenderer, placeholderColor: presentationInterfaceState.theme.chat.inputPanel.inputTextColor.withAlphaComponent(0.12), pointSize: CGSize(width: 24.0, height: 24.0))
}
self.updateSendButtonEnabled(isCaption || isAttachment, animated: false)

View File

@ -984,7 +984,7 @@ public class AttachmentController: ViewController {
let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
let accountResource = context.account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true)
let fetchedFullSize = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource))
let fetchedFullSize = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: file), reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource))
let fetchedFullSizeDisposable = fetchedFullSize.start()
let fullSizeDisposable = accountResource.start()
@ -996,7 +996,7 @@ public class AttachmentController: ViewController {
disposableSet.add(accountFullSizeData.start())
}
} else {
disposableSet.add(freeMediaFileInteractiveFetched(account: context.account, fileReference: .attachBot(peer: peer, media: file)).start())
disposableSet.add(freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: .attachBot(peer: peer, media: file)).start())
}
}
}

View File

@ -833,7 +833,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
let accountResource = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true)
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource))
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: file), reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource))
let fetchedFullSizeDisposable = fetchedFullSize.start()
let fullSizeDisposable = accountResource.start()
@ -845,7 +845,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
self.iconDisposables[file.fileId] = accountFullSizeData.start()
}
} else {
self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start()
self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .attachBot(peer: peer, media: file)).start()
}
}
}

View File

@ -65,11 +65,11 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
})
var fetchedDataDisposable: Disposable?
if let peerReference = peerReference {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start()
} else if let authorOfMessage = authorOfMessage {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start()
} else {
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start()
fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start()
}
return ActionDisposable {
resourceDataDisposable.dispose()

View File

@ -23,14 +23,16 @@ import Markdown
final class BotCheckoutControllerArguments {
fileprivate let account: Account
fileprivate let source: BotPaymentInvoiceSource
fileprivate let openInfo: (BotCheckoutInfoControllerFocus) -> Void
fileprivate let openPaymentMethod: () -> Void
fileprivate let openShippingMethod: () -> Void
fileprivate let updateTip: (Int64) -> Void
fileprivate let ensureTipInputVisible: () -> Void
fileprivate init(account: Account, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void, updateTip: @escaping (Int64) -> Void, ensureTipInputVisible: @escaping () -> Void) {
fileprivate init(account: Account, source: BotPaymentInvoiceSource, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void, updateTip: @escaping (Int64) -> Void, ensureTipInputVisible: @escaping () -> Void) {
self.account = account
self.source = source
self.openInfo = openInfo
self.openPaymentMethod = openPaymentMethod
self.openShippingMethod = openShippingMethod
@ -245,7 +247,7 @@ enum BotCheckoutEntry: ItemListNodeEntry {
let arguments = arguments as! BotCheckoutControllerArguments
switch self {
case let .header(theme, invoice, botName):
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, botName: botName, sectionId: self.section)
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, source: arguments.source, botName: botName, sectionId: self.section)
case let .price(_, theme, text, value, isFinal, hasSeparator, shimmeringIndex):
return BotCheckoutPriceItem(theme: theme, title: text, label: value, isFinal: isFinal, hasSeparator: hasSeparator, shimmeringIndex: shimmeringIndex, sectionId: self.section)
case let .tip(_, _, text, currency, value, numericValue, maxValue, variants):
@ -712,7 +714,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
var openShippingMethodImpl: (() -> Void)?
var ensureTipInputVisibleImpl: (() -> Void)?
let arguments = BotCheckoutControllerArguments(account: context.account, openInfo: { item in
let arguments = BotCheckoutControllerArguments(account: context.account, source: source, openInfo: { item in
openInfoImpl?(item)
}, openPaymentMethod: {
openPaymentMethodImpl?()

View File

@ -14,13 +14,15 @@ class BotCheckoutHeaderItem: ListViewItem, ItemListItem {
let account: Account
let theme: PresentationTheme
let invoice: TelegramMediaInvoice
let source: BotPaymentInvoiceSource
let botName: String
let sectionId: ItemListSectionId
init(account: Account, theme: PresentationTheme, invoice: TelegramMediaInvoice, botName: String, sectionId: ItemListSectionId) {
init(account: Account, theme: PresentationTheme, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, botName: String, sectionId: ItemListSectionId) {
self.account = account
self.theme = theme
self.invoice = invoice
self.source = source
self.botName = botName
self.sectionId = sectionId
}
@ -173,7 +175,15 @@ class BotCheckoutHeaderItemNode: ListViewItemNode {
maxTextWidth = max(1.0, maxTextWidth - imageSize.width - imageTextSpacing)
if imageUpdated {
updatedImageSignal = chatWebFileImage(account: item.account, file: photo)
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, reference: .standalone(resource: photo.resource))
var userLocation: MediaResourceUserLocation = .other
switch item.source {
case let .message(messageId):
userLocation = .peer(messageId.peerId)
default:
break
}
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: .standalone(resource: photo.resource))
}
}

View File

@ -12,9 +12,11 @@ import TelegramStringFormatting
final class BotReceiptControllerArguments {
fileprivate let account: Account
fileprivate let source: BotPaymentInvoiceSource
fileprivate init(account: Account) {
fileprivate init(account: Account, source: BotPaymentInvoiceSource) {
self.account = account
self.source = source
}
}
@ -154,7 +156,7 @@ enum BotReceiptEntry: ItemListNodeEntry {
let arguments = arguments as! BotReceiptControllerArguments
switch self {
case let .header(theme, invoice, botName):
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, botName: botName, sectionId: self.section)
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, source: arguments.source, botName: botName, sectionId: self.section)
case let .price(_, theme, text, value, hasSeparator, isFinal):
return BotCheckoutPriceItem(theme: theme, title: text, label: value, isFinal: isFinal, hasSeparator: hasSeparator, shimmeringIndex: nil, sectionId: self.section)
case let .paymentMethod(_, text, value):
@ -284,7 +286,7 @@ final class BotReceiptControllerNode: ItemListControllerNode {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let arguments = BotReceiptControllerArguments(account: context.account)
let arguments = BotReceiptControllerArguments(account: context.account, source: .message(messageId))
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(
context.sharedContext.presentationData,

View File

@ -442,7 +442,7 @@ public final class ChatImportActivityScreen: ViewController {
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: 12345), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: size, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
let videoContent = NativeVideoContent(id: .message(1, MediaId(namespace: 0, id: 1)), fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
let videoContent = NativeVideoContent(id: .message(1, MediaId(namespace: 0, id: 1)), userLocation: .other, fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
let videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded)
videoNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: 2.0))

View File

@ -2086,7 +2086,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
interaction.openUrl(url)
}, openInstantPage: { [weak self] message, data in
if let (webpage, anchor) = instantPageAndAnchor(message: message) {
let pageController = InstantPageController(context: context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)
let pageController = InstantPageController(context: context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: .peer(message.id.peerId), peerType: .channel), anchor: anchor)
self?.navigationController?.pushViewController(pageController)
}
}, longTap: { action, message in

View File

@ -201,7 +201,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions {
mediaDimensions = largestSize.cgSize
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true)
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true)
self.fetchStatusDisposable.set(nil)
self.statusNode.transitionToState(.none, completion: { [weak self] in
@ -211,7 +211,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
self.resourceStatus = nil
} else if let file = media as? TelegramMediaFile, file.isVideo {
mediaDimensions = file.dimensions?.cgSize
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad)
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad)
self.mediaBadgeNode.isHidden = file.isAnimated

View File

@ -569,7 +569,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
dimensions = largest.dimensions.cgSize
if !self.requestedImage {
self.requestedImage = true
let signal = mediaGridMessagePhoto(account: self.context.account, photoReference: .message(message: MessageReference(self.message._asMessage()), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads)
let signal = mediaGridMessagePhoto(account: self.context.account, userLocation: .peer(self.message.id.peerId), photoReference: .message(message: MessageReference(self.message._asMessage()), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads)
self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoads)
}
}
@ -580,7 +580,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
dimensions = largest.dimensions.cgSize
if !self.requestedImage {
self.requestedImage = true
let signal = mediaGridMessagePhoto(account: self.context.account, photoReference: .message(message: MessageReference(self.message._asMessage()), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads)
let signal = mediaGridMessagePhoto(account: self.context.account, userLocation: .peer(self.message.id.peerId), photoReference: .message(message: MessageReference(self.message._asMessage()), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads)
self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoads)
}
}
@ -597,7 +597,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
dimensions = mediaDimensions.cgSize
if !self.requestedImage {
self.requestedImage = true
let signal = mediaGridMessageVideo(postbox: self.context.account.postbox, videoReference: .message(message: MessageReference(self.message._asMessage()), media: file), synchronousLoad: synchronousLoads, autoFetchFullSizeThumbnail: true, useMiniThumbnailIfAvailable: true)
let signal = mediaGridMessageVideo(postbox: self.context.account.postbox, userLocation: .peer(self.message.id.peerId), videoReference: .message(message: MessageReference(self.message._asMessage()), media: file), synchronousLoad: synchronousLoads, autoFetchFullSizeThumbnail: true, useMiniThumbnailIfAvailable: true)
self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoads)
}
}
@ -1326,7 +1326,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if let photo = photo, let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
let videoId = photo.id?.id ?? peer.id.id._internalGetInt64Value()
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(videoId, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
let videoContent = NativeVideoContent(id: .profileVideo(videoId, nil), userLocation: .other, fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: false)
if videoContent.id != strongSelf.videoContent?.id {
strongSelf.videoNode?.removeFromSupernode()
strongSelf.videoContent = videoContent

View File

@ -143,6 +143,7 @@ public final class ReactionIconView: PortalSourceView {
let animationLayer = InlineStickerItemLayer(
context: context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(
interactivelySelectedFromPackId: nil,

View File

@ -19,7 +19,7 @@ public let sharedReactionStaticImage = Queue(name: "SharedReactionStaticImage",
public func reactionStaticImage(context: AccountContext, animation: TelegramMediaFile, pixelSize: CGSize, queue: Queue) -> Signal<EngineMediaResource.ResourceData, NoError> {
return context.engine.resources.custom(id: "\(animation.resource.id.stringRepresentation):reaction-static-\(pixelSize.width)x\(pixelSize.height)-v10", fetch: EngineMediaResource.Fetch {
return Signal { subscriber in
let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: MediaResourceReference.standalone(resource: animation.resource)).start()
let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: MediaResourceReference.standalone(resource: animation.resource)).start()
let type: AnimationCacheAnimationType
if animation.isVideoSticker || animation.isVideoEmoji {
@ -39,7 +39,7 @@ public func reactionStaticImage(context: AccountContext, animation: TelegramMedi
}
}
let fetchFrame = animationCacheFetchFile(context: context, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true, customColor: customColor)
let fetchFrame = animationCacheFetchFile(context: context, userLocation: .other, userContentType: .emoji, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true, customColor: customColor)
class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
let queue: Queue

View File

@ -195,6 +195,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
let reactionLayer = InlineStickerItemLayer(
context: context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file),
file: file,
@ -437,6 +438,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
let reactionLayer = InlineStickerItemLayer(
context: context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file),
file: file,

View File

@ -188,12 +188,14 @@ public final class DirectMediaImageCache {
return self.account.postbox.mediaBox.cachedRepresentationPathForId(resourceId.stringRepresentation, representationId: representationId, keepDuration: .general)
}
private func getLoadSignal(width: Int, resource: MediaResourceReference, resourceSizeLimit: Int64) -> Signal<UIImage?, NoError>? {
private func getLoadSignal(width: Int, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resource: MediaResourceReference, resourceSizeLimit: Int64) -> Signal<UIImage?, NoError>? {
return Signal { subscriber in
let cachePath = self.getCachePath(resourceId: resource.resource.id, imageType: .square(width: width))
let fetch = fetchedMediaResource(
mediaBox: self.account.postbox.mediaBox,
userLocation: userLocation,
userContentType: userContentType,
reference: resource,
ranges: [(0 ..< resourceSizeLimit, .default)],
statsCategory: .image,
@ -282,7 +284,7 @@ public final class DirectMediaImageCache {
return self.getProgressiveSize(mediaReference: MediaReference.message(message: MessageReference(message), media: file).abstract, width: width, representations: file.previewRepresentations)
}
private func getImageSynchronous(message: Message, media: Media, width: Int, possibleWidths: [Int]) -> GetMediaResult? {
private func getImageSynchronous(message: Message, userLocation: MediaResourceUserLocation, media: Media, width: Int, possibleWidths: [Int]) -> GetMediaResult? {
var immediateThumbnailData: Data?
var resource: (resource: MediaResourceReference, size: Int64)?
if let image = media as? TelegramMediaImage {
@ -320,15 +322,15 @@ public final class DirectMediaImageCache {
}
}
return GetMediaResult(image: blurredImage, loadSignal: self.getLoadSignal(width: width, resource: resource.resource, resourceSizeLimit: resource.size))
return GetMediaResult(image: blurredImage, loadSignal: self.getLoadSignal(width: width, userLocation: userLocation, userContentType: .image, resource: resource.resource, resourceSizeLimit: resource.size))
}
public func getImage(message: Message, media: Media, width: Int, possibleWidths: [Int], synchronous: Bool) -> GetMediaResult? {
if synchronous {
return self.getImageSynchronous(message: message, media: media, width: width, possibleWidths: possibleWidths)
return self.getImageSynchronous(message: message, userLocation: .peer(message.id.peerId), media: media, width: width, possibleWidths: possibleWidths)
} else {
return GetMediaResult(image: nil, loadSignal: Signal { subscriber in
let result = self.getImageSynchronous(message: message, media: media, width: width, possibleWidths: possibleWidths)
let result = self.getImageSynchronous(message: message, userLocation: .peer(message.id.peerId), media: media, width: width, possibleWidths: possibleWidths)
guard let result = result else {
subscriber.putNext(nil)
subscriber.putCompletion()

View File

@ -121,8 +121,8 @@ final class DrawingStickerEntityView: DrawingEntityView {
self.addSubnode(animationNode)
}
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start())
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start())
} else {
if let animationNode = self.animationNode {
animationNode.visibility = false
@ -131,8 +131,8 @@ final class DrawingStickerEntityView: DrawingEntityView {
self.imageNode.isHidden = false
self.didSetUpAnimationNode = false
}
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, file: self.file, small: false, synchronousLoad: false))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start())
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, userLocation: .other, file: self.file, small: false, synchronousLoad: false))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start())
}
self.dimensions = dimensions.cgSize

View File

@ -238,7 +238,23 @@ private final class FetchManagerCategoryContext {
activeContext.disposable?.dispose()
let postbox = self.postbox
Logger.shared.log("FetchManager", "Begin fetching \(entry.resourceReference.resource.id.stringRepresentation) ranges: \(String(describing: parsedRanges))")
activeContext.disposable = (fetchedMediaResource(mediaBox: postbox.mediaBox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
var userLocation: MediaResourceUserLocation = .other
switch entry.id.location {
case let .chat(peerId):
userLocation = .peer(peerId)
}
var userContentType: MediaResourceUserContentType = .other
switch entry.statsCategory {
case .image:
userContentType = .image
case .video:
userContentType = .video
default:
userContentType = .other
}
activeContext.disposable = (fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if filterDownloadStatsEntry(entry: entry), case let .message(message, _) = entry.mediaReference, let messageId = message.id, case .remote = type {
let _ = addRecentDownloadItem(postbox: postbox, item: RecentDownloadItem(messageId: messageId, resourceId: entry.resourceReference.resource.id.stringRepresentation, timestamp: Int32(Date().timeIntervalSince1970), isSeen: false)).start()
@ -349,11 +365,26 @@ private final class FetchManagerCategoryContext {
if restart {
activeContext.ranges = ranges
var userLocation: MediaResourceUserLocation = .other
switch entry.id.location {
case let .chat(peerId):
userLocation = .peer(peerId)
}
var userContentType: MediaResourceUserContentType = .other
switch entry.statsCategory {
case .image:
userContentType = .image
case .video:
userContentType = .video
default:
userContentType = .other
}
let entryCompleted = self.entryCompleted
let storeManager = self.storeManager
activeContext.disposable?.dispose()
if isVideoPreload {
activeContext.disposable = (preloadVideoResource(postbox: self.postbox, resourceReference: entry.resourceReference, duration: 4.0)
activeContext.disposable = (preloadVideoResource(postbox: self.postbox, userLocation: userLocation, userContentType: userContentType, resourceReference: entry.resourceReference, duration: 4.0)
|> castError(FetchResourceError.self)
|> map { _ -> FetchResourceSourceType in }
|> then(.single(.local))
@ -364,7 +395,23 @@ private final class FetchManagerCategoryContext {
} else {
let postbox = self.postbox
Logger.shared.log("FetchManager", "Begin fetching \(entry.resourceReference.resource.id.stringRepresentation) ranges: \(String(describing: parsedRanges))")
activeContext.disposable = (fetchedMediaResource(mediaBox: postbox.mediaBox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
var userLocation: MediaResourceUserLocation = .other
switch entry.id.location {
case let .chat(peerId):
userLocation = .peer(peerId)
}
var userContentType: MediaResourceUserContentType = .other
switch entry.statsCategory {
case .image:
userContentType = .image
case .video:
userContentType = .video
default:
userContentType = .other
}
activeContext.disposable = (fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if filterDownloadStatsEntry(entry: entry), case let .message(message, _) = entry.mediaReference, let messageId = message.id, case .remote = type {
let _ = addRecentDownloadItem(postbox: postbox, item: RecentDownloadItem(messageId: messageId, resourceId: entry.resourceReference.resource.id.stringRepresentation, timestamp: Int32(Date().timeIntervalSince1970), isSeen: false)).start()

View File

@ -192,7 +192,7 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
}
}
let gallery = InstantPageGalleryController(context: context, webPage: webPage, message: message, entries: instantPageMedia, centralIndex: centralIndex, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, replaceRootController: { [weak navigationController] controller, ready in
let gallery = InstantPageGalleryController(context: context, userLocation: chatLocation?.peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, webPage: webPage, message: message, entries: instantPageMedia, centralIndex: centralIndex, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, replaceRootController: { [weak navigationController] controller, ready in
if let navigationController = navigationController {
navigationController.replaceTopController(controller, animated: false, ready: ready)
}

View File

@ -156,12 +156,12 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese
if file.isVideo {
let content: UniversalVideoContent
if file.isAnimated {
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), loopVideo: true, enableSound: false, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
content = NativeVideoContent(id: .message(message.stableId, file.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), loopVideo: true, enableSound: false, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
} else {
if true || (file.mimeType == "video/mpeg4" || file.mimeType == "video/mov" || file.mimeType == "video/mp4") {
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
content = NativeVideoContent(id: .message(message.stableId, file.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
} else {
content = PlatformVideoContent(id: .message(message.id, message.stableId, file.fileId), content: .file(.message(message: MessageReference(message), media: file)), streamVideo: streamVideos, loopVideo: loopVideos)
content = PlatformVideoContent(id: .message(message.id, message.stableId, file.fileId), userLocation: .peer(message.id.peerId), content: .file(.message(message: MessageReference(message), media: file)), streamVideo: streamVideos, loopVideo: loopVideos)
}
}
@ -204,16 +204,16 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese
var content: UniversalVideoContent?
switch websiteType(of: webpageContent.websiteName) {
case .instagram where webpageContent.file != nil && webpageContent.image != nil && webpageContent.file!.isVideo:
content = NativeVideoContent(id: .message(message.stableId, webpageContent.file?.id ?? webpage.webpageId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), imageReference: webpageContent.image.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, enableSound: true, captureProtected: message.isCopyProtected())
content = NativeVideoContent(id: .message(message.stableId, webpageContent.file?.id ?? webpage.webpageId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), imageReference: webpageContent.image.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, enableSound: true, captureProtected: message.isCopyProtected())
default:
if let embedUrl = webpageContent.embedUrl, let image = webpageContent.image {
if let file = webpageContent.file, file.isVideo {
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
content = NativeVideoContent(id: .message(message.stableId, file.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath, captureProtected: message.isCopyProtected())
} else if URL(string: embedUrl)?.pathExtension == "mp4" {
content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize?.cgSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
content = SystemVideoContent(userLocation: .peer(message.id.peerId), url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize?.cgSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
}
}
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init), openUrl: { url in
if content == nil, let webEmbedContent = WebEmbedVideoContent(userLocation: .peer(message.id.peerId), webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init), openUrl: { url in
performAction(.url(url: url.absoluteString, concealed: false))
}) {
content = webEmbedContent

View File

@ -345,7 +345,7 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode {
case .Fetching:
self.context.account.postbox.mediaBox.cancelInteractiveResourceFetch(resource.resource)
case .Remote:
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: resource, statsCategory: statsCategory ?? .generic).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: (self.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, userContentType: .file, reference: resource, statsCategory: statsCategory ?? .generic).start())
default:
break
}

View File

@ -388,7 +388,7 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD
case .Fetching:
context.account.postbox.mediaBox.cancelInteractiveResourceFetch(fileReference.media.resource)
case .Remote:
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: (self.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, userContentType: .file, reference: fileReference.resourceReference(fileReference.media.resource)).start())
default:
break
}

View File

@ -323,7 +323,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
case .Fetching:
context.account.postbox.mediaBox.cancelInteractiveResourceFetch(fileReference.media.resource)
case .Remote:
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: (self.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, userContentType: .file, reference: fileReference.resourceReference(fileReference.media.resource)).start())
default:
break
}

View File

@ -52,10 +52,12 @@ enum ChatMediaGalleryThumbnail: Equatable {
final class ChatMediaGalleryThumbnailItem: GalleryThumbnailItem {
private let account: Account
private let userLocation: MediaResourceUserLocation
private let thumbnail: ChatMediaGalleryThumbnail
init?(account: Account, mediaReference: AnyMediaReference) {
init?(account: Account, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) {
self.account = account
self.userLocation = userLocation
if let imageReference = mediaReference.concrete(TelegramMediaImage.self) {
self.thumbnail = .image(imageReference)
} else if let fileReference = mediaReference.concrete(TelegramMediaFile.self) {
@ -81,19 +83,19 @@ final class ChatMediaGalleryThumbnailItem: GalleryThumbnailItem {
switch self.thumbnail {
case let .image(imageReference):
if let representation = largestImageRepresentation(imageReference.media.representations) {
return (mediaGridMessagePhoto(account: self.account, photoReference: imageReference), representation.dimensions.cgSize)
return (mediaGridMessagePhoto(account: self.account, userLocation: self.userLocation, photoReference: imageReference), representation.dimensions.cgSize)
} else {
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
}
case let .video(fileReference):
if let representation = largestImageRepresentation(fileReference.media.previewRepresentations) {
return (mediaGridMessageVideo(postbox: self.account.postbox, videoReference: fileReference), representation.dimensions.cgSize)
return (mediaGridMessageVideo(postbox: self.account.postbox, userLocation: self.userLocation, videoReference: fileReference), representation.dimensions.cgSize)
} else {
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
}
case let .file(fileReference):
if let representation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
return (chatWebpageSnippetFile(account: self.account, mediaReference: fileReference.abstract, representation: representation), representation.dimensions.cgSize)
return (chatWebpageSnippetFile(account: self.account, userLocation: self.userLocation, mediaReference: fileReference.abstract, representation: representation), representation.dimensions.cgSize)
} else {
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
}
@ -132,19 +134,19 @@ class ChatImageGalleryItem: GalleryItem {
node.setMessage(self.message, displayInfo: !self.displayInfoOnTop)
for media in self.message.media {
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia, let image = fullMedia as? TelegramMediaImage {
node.setImage(imageReference: .message(message: MessageReference(self.message), media: image))
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
} else if let image = media as? TelegramMediaImage {
node.setImage(imageReference: .message(message: MessageReference(self.message), media: image))
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
break
} else if let file = media as? TelegramMediaFile, file.mimeType.hasPrefix("image/") {
node.setFile(context: self.context, fileReference: .message(message: MessageReference(self.message), media: file))
node.setFile(context: self.context, userLocation: .peer(self.message.id.peerId), fileReference: .message(message: MessageReference(self.message), media: file))
break
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
if let image = content.image {
node.setImage(imageReference: .message(message: MessageReference(self.message), media: image))
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
break
} else if let file = content.file, file.mimeType.hasPrefix("image/") {
node.setFile(context: self.context, fileReference: .message(message: MessageReference(self.message), media: file))
node.setFile(context: self.context, userLocation: .peer(self.message.id.peerId), fileReference: .message(message: MessageReference(self.message), media: file))
break
}
}
@ -183,7 +185,7 @@ class ChatImageGalleryItem: GalleryItem {
}
}
if let mediaReference = mediaReference {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, mediaReference: mediaReference) {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, userLocation: .peer(self.message.id.peerId), mediaReference: mediaReference) {
return (Int64(id), item)
}
}
@ -323,12 +325,12 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.footerContentNode.setMessage(message, displayInfo: displayInfo)
}
fileprivate func setImage(imageReference: ImageMediaReference) {
fileprivate func setImage(userLocation: MediaResourceUserLocation, imageReference: ImageMediaReference) {
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: imageReference.media) {
if let largestSize = largestRepresentationForPhoto(imageReference.media) {
let displaySize = largestSize.dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
let signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError> = chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: self.context.account.postbox, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: false), synchronousLoad: false)
let signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError> = chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: self.context.account.postbox, userLocation: userLocation, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: false), synchronousLoad: false)
|> map { [weak self] _, quality, generate -> (TransformImageArguments) -> DrawingContext? in
Queue.mainQueue().async {
guard let strongSelf = self else {
@ -418,7 +420,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.zoomableContent = (largestSize.dimensions.cgSize, self.imageNode)
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: imageReference.resourceReference(largestSize.resource)).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: imageReference.resourceReference(largestSize.resource)).start())
self.setupStatus(resource: largestSize.resource)
} else {
self._ready.set(.single(Void()))
@ -643,7 +645,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
})
}
func setFile(context: AccountContext, fileReference: FileMediaReference) {
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) {
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
if var largestSize = fileReference.media.dimensions {
var displaySize = largestSize.cgSize.dividedByScreenScale()
@ -669,7 +671,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
strongSelf.updateImageFromFile(path: data.path)
}))
} else {*/
self.imageNode.setSignal(chatMessageImageFile(account: context.account, fileReference: fileReference, thumbnail: false), dispatchOnDisplayLink: false)
self.imageNode.setSignal(chatMessageImageFile(account: context.account, userLocation: userLocation, fileReference: fileReference, thumbnail: false), dispatchOnDisplayLink: false)
//}
self.zoomableContent = (largestSize.cgSize, self.imageNode)
@ -932,7 +934,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
case .Fetching:
self.context.account.postbox.mediaBox.cancelInteractiveResourceFetch(resource.resource)
case .Remote:
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: resource, statsCategory: statsCategory ?? .generic).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: (self.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, userContentType: .image, reference: resource, statsCategory: statsCategory ?? .generic).start())
default:
break
}

View File

@ -126,13 +126,13 @@ public class UniversalVideoGalleryItem: GalleryItem {
}
}
if let mediaReference = mediaReference {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, mediaReference: mediaReference) {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, userLocation: .peer(message.id.peerId), mediaReference: mediaReference) {
return (Int64(id), item)
}
}
}
} else if case let .webPage(webPage, media, _) = contentInfo, let file = media as? TelegramMediaFile {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, mediaReference: .webPage(webPage: WebpageReference(webPage), media: file)) {
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, userLocation: .other, mediaReference: .webPage(webPage: WebpageReference(webPage), media: file)) {
return (0, item)
}
}
@ -1102,7 +1102,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var isEnhancedWebPlayer = false
if let content = item.content as? NativeVideoContent {
isAnimated = content.fileReference.media.isAnimated
self.videoFramePreview = MediaPlayerFramePreview(postbox: item.context.account.postbox, fileReference: content.fileReference)
self.videoFramePreview = MediaPlayerFramePreview(postbox: item.context.account.postbox, userLocation: content.userLocation, userContentType: .video, fileReference: content.fileReference)
} else if let _ = item.content as? SystemVideoContent {
self._title.set(.single(item.presentationData.strings.Message_Video))
} else if let content = item.content as? WebEmbedVideoContent {
@ -2565,7 +2565,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let strongSelf = self {
switch strongSelf.fetchStatus {
case .Local:
let _ = (SaveToCameraRoll.saveToCameraRoll(context: strongSelf.context, postbox: strongSelf.context.account.postbox, mediaReference: .message(message: MessageReference(message), media: file))
let _ = (SaveToCameraRoll.saveToCameraRoll(context: strongSelf.context, postbox: strongSelf.context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: .message(message: MessageReference(message), media: file))
|> deliverOnMainQueue).start(completed: {
guard let strongSelf = self else {
return

View File

@ -12,13 +12,14 @@ import GalleryUI
private struct InstantImageGalleryThumbnailItem: GalleryThumbnailItem {
let account: Account
let userLocation: MediaResourceUserLocation
let mediaReference: AnyMediaReference
func image(synchronous: Bool) -> (Signal<(TransformImageArguments) -> DrawingContext?, NoError>, CGSize) {
if let imageReferene = mediaReference.concrete(TelegramMediaImage.self), let representation = largestImageRepresentation(imageReferene.media.representations) {
return (mediaGridMessagePhoto(account: self.account, photoReference: imageReferene), representation.dimensions.cgSize)
return (mediaGridMessagePhoto(account: self.account, userLocation: self.userLocation, photoReference: imageReferene), representation.dimensions.cgSize)
} else if let fileReference = mediaReference.concrete(TelegramMediaFile.self), let dimensions = fileReference.media.dimensions {
return (mediaGridMessageVideo(postbox: account.postbox, videoReference: fileReference), dimensions.cgSize)
return (mediaGridMessageVideo(postbox: account.postbox, userLocation: self.userLocation, videoReference: fileReference), dimensions.cgSize)
} else {
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
}
@ -42,6 +43,7 @@ class InstantImageGalleryItem: GalleryItem {
let context: AccountContext
let presentationData: PresentationData
let userLocation: MediaResourceUserLocation
let imageReference: ImageMediaReference
let caption: NSAttributedString
let credit: NSAttributedString
@ -49,8 +51,9 @@ class InstantImageGalleryItem: GalleryItem {
let openUrl: (InstantPageUrlItem) -> Void
let openUrlOptions: (InstantPageUrlItem) -> Void
init(context: AccountContext, presentationData: PresentationData, itemId: AnyHashable, imageReference: ImageMediaReference, caption: NSAttributedString, credit: NSAttributedString, location: InstantPageGalleryEntryLocation?, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) {
init(context: AccountContext, presentationData: PresentationData, itemId: AnyHashable, userLocation: MediaResourceUserLocation, imageReference: ImageMediaReference, caption: NSAttributedString, credit: NSAttributedString, location: InstantPageGalleryEntryLocation?, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) {
self.itemId = itemId
self.userLocation = userLocation
self.context = context
self.presentationData = presentationData
self.imageReference = imageReference
@ -64,7 +67,7 @@ class InstantImageGalleryItem: GalleryItem {
func node(synchronous: Bool) -> GalleryItemNode {
let node = InstantImageGalleryItemNode(context: self.context, presentationData: self.presentationData, openUrl: self.openUrl, openUrlOptions: self.openUrlOptions)
node.setImage(imageReference: self.imageReference)
node.setImage(userLocation: self.userLocation, imageReference: self.imageReference)
if let location = self.location {
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.position + 1)", "\(location.totalCount)").string))
@ -86,7 +89,7 @@ class InstantImageGalleryItem: GalleryItem {
}
func thumbnailItem() -> (Int64, GalleryThumbnailItem)? {
return (0, InstantImageGalleryThumbnailItem(account: self.context.account, mediaReference: imageReference.abstract))
return (0, InstantImageGalleryThumbnailItem(account: self.context.account, userLocation: self.userLocation, mediaReference: imageReference.abstract))
}
}
@ -98,6 +101,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
fileprivate let _title = Promise<String>()
private let footerContentNode: InstantPageGalleryFooterContentNode
private var userLocation: MediaResourceUserLocation?
private var contextAndMedia: (AccountContext, AnyMediaReference)?
private var fetchDisposable = MetaDisposable()
@ -136,14 +140,16 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.footerContentNode.setCaption(caption, credit: credit)
}
fileprivate func setImage(imageReference: ImageMediaReference) {
fileprivate func setImage(userLocation: MediaResourceUserLocation, imageReference: ImageMediaReference) {
self.userLocation = userLocation
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: imageReference.media) {
if let largestSize = largestRepresentationForPhoto(imageReference.media) {
let displaySize = largestSize.dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), emptyColor: .black))()
self.imageNode.setSignal(chatMessagePhoto(postbox: self.context.account.postbox, photoReference: imageReference), dispatchOnDisplayLink: false)
self.imageNode.setSignal(chatMessagePhoto(postbox: self.context.account.postbox, userLocation: userLocation, photoReference: imageReference), dispatchOnDisplayLink: false)
self.zoomableContent = (largestSize.dimensions.cgSize, self.imageNode)
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: imageReference.resourceReference(largestSize.resource)).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: imageReference.resourceReference(largestSize.resource)).start())
} else {
self._ready.set(.single(Void()))
}
@ -152,12 +158,14 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.footerContentNode.setShareMedia(imageReference.abstract)
}
func setFile(context: AccountContext, fileReference: FileMediaReference) {
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) {
self.userLocation = userLocation
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
if let largestSize = fileReference.media.dimensions {
let displaySize = largestSize.cgSize.dividedByScreenScale()
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
self.imageNode.setSignal(chatMessageImageFile(account: context.account, fileReference: fileReference, thumbnail: false), dispatchOnDisplayLink: false)
self.imageNode.setSignal(chatMessageImageFile(account: context.account, userLocation: userLocation, fileReference: fileReference, thumbnail: false), dispatchOnDisplayLink: false)
self.zoomableContent = (largestSize.cgSize, self.imageNode)
} else {
self._ready.set(.single(Void()))
@ -296,7 +304,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
if let (context, media) = self.contextAndMedia, let fileReference = media.concrete(TelegramMediaFile.self) {
if isVisible {
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: self.userLocation ?? .other, userContentType: .file, reference: fileReference.resourceReference(fileReference.media.resource)).start())
} else {
self.fetchDisposable.set(nil)
}

View File

@ -28,7 +28,7 @@ final class InstantPageAnchorItem: InstantPageItem {
func drawInTile(context: CGContext) {
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return nil
}

View File

@ -13,6 +13,7 @@ final class InstantPageArticleItem: InstantPageItem {
let wantsNode: Bool = true
let separatesTiles: Bool = false
let medias: [InstantPageMedia] = []
let userLocation: MediaResourceUserLocation
let webPage: TelegramMediaWebpage
let contentItems: [InstantPageItem]
@ -23,8 +24,9 @@ final class InstantPageArticleItem: InstantPageItem {
let rtl: Bool
let hasRTL: Bool
init(frame: CGRect, webPage: TelegramMediaWebpage, contentItems: [InstantPageItem], contentSize: CGSize, cover: TelegramMediaImage?, url: String, webpageId: MediaId, rtl: Bool, hasRTL: Bool) {
init(frame: CGRect, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, contentItems: [InstantPageItem], contentSize: CGSize, cover: TelegramMediaImage?, url: String, webpageId: MediaId, rtl: Bool, hasRTL: Bool) {
self.frame = frame
self.userLocation = userLocation
self.webPage = webPage
self.contentItems = contentItems
self.contentSize = contentSize
@ -35,7 +37,7 @@ final class InstantPageArticleItem: InstantPageItem {
self.hasRTL = hasRTL
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageArticleNode(context: context, item: self, webPage: self.webPage, strings: strings, theme: theme, contentItems: self.contentItems, contentSize: self.contentSize, cover: self.cover, url: self.url, webpageId: self.webpageId, openUrl: openUrl)
}
@ -71,7 +73,7 @@ final class InstantPageArticleItem: InstantPageItem {
}
}
func layoutArticleItem(theme: InstantPageTheme, webPage: TelegramMediaWebpage, title: NSAttributedString, description: NSAttributedString, cover: TelegramMediaImage?, url: String, webpageId: MediaId, boundingWidth: CGFloat, rtl: Bool) -> InstantPageArticleItem {
func layoutArticleItem(theme: InstantPageTheme, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, title: NSAttributedString, description: NSAttributedString, cover: TelegramMediaImage?, url: String, webpageId: MediaId, boundingWidth: CGFloat, rtl: Bool) -> InstantPageArticleItem {
let inset: CGFloat = 17.0
let imageSpacing: CGFloat = 10.0
var sideInset = inset
@ -116,5 +118,5 @@ func layoutArticleItem(theme: InstantPageTheme, webPage: TelegramMediaWebpage, t
}
let contentSize = CGSize(width: boundingWidth, height: contentHeight)
return InstantPageArticleItem(frame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: contentSize.height)), webPage: webPage, contentItems: contentItems, contentSize: contentSize, cover: cover, url: url, webpageId: webpageId, rtl: rtl || hasRTL, hasRTL: hasRTL)
return InstantPageArticleItem(frame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: contentSize.height)), userLocation: userLocation, webPage: webPage, contentItems: contentItems, contentSize: contentSize, cover: cover, url: url, webpageId: webpageId, rtl: rtl || hasRTL, hasRTL: hasRTL)
}

View File

@ -55,8 +55,8 @@ final class InstantPageArticleNode: ASDisplayNode, InstantPageNode {
imageNode.isUserInteractionEnabled = false
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference))
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: item.userLocation, photoReference: imageReference))
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: item.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
self.imageNode = imageNode
self.addSubnode(imageNode)

View File

@ -24,7 +24,7 @@ final class InstantPageAudioItem: InstantPageItem {
self.medias = [media]
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageAudioNode(context: context, strings: strings, theme: theme, webPage: self.webpage, media: self.media, openMedia: openMedia)
}

View File

@ -13,7 +13,7 @@ final class InstantPageContentNode : ASDisplayNode {
private let context: AccountContext
private let strings: PresentationStrings
private let nameDisplayOrder: PresentationPersonNameOrder
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let theme: InstantPageTheme
private let openMedia: (InstantPageMedia) -> Void
@ -40,11 +40,11 @@ final class InstantPageContentNode : ASDisplayNode {
private var previousVisibleBounds: CGRect?
init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) {
init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) {
self.context = context
self.strings = strings
self.nameDisplayOrder = nameDisplayOrder
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.theme = theme
self.openMedia = openMedia
@ -188,7 +188,7 @@ final class InstantPageContentNode : ASDisplayNode {
if itemNode == nil {
let itemIndex = itemIndex
let detailsIndex = detailsIndex
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourcePeerType: self.sourcePeerType, openMedia: { [weak self] media in
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourceLocation: self.sourceLocation, openMedia: { [weak self] media in
self?.openMedia(media)
}, longPressMedia: { [weak self] media in
self?.longPressMedia(media)

View File

@ -8,6 +8,16 @@ import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
public struct InstantPageSourceLocation {
public var userLocation: MediaResourceUserLocation
public var peerType: MediaAutoDownloadPeerType
public init(userLocation: MediaResourceUserLocation, peerType: MediaAutoDownloadPeerType) {
self.userLocation = userLocation
self.peerType = peerType
}
}
public func instantPageAndAnchor(message: Message) -> (TelegramMediaWebpage, String?)? {
for media in message.media {
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
@ -61,7 +71,7 @@ public func instantPageAndAnchor(message: Message) -> (TelegramMediaWebpage, Str
public final class InstantPageController: ViewController {
private let context: AccountContext
private var webPage: TelegramMediaWebpage
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let anchor: String?
private var presentationData: PresentationData
@ -82,13 +92,13 @@ public final class InstantPageController: ViewController {
private var settingsDisposable: Disposable?
private var themeSettings: PresentationThemeSettings?
public init(context: AccountContext, webPage: TelegramMediaWebpage, sourcePeerType: MediaAutoDownloadPeerType, anchor: String? = nil) {
public init(context: AccountContext, webPage: TelegramMediaWebpage, sourceLocation: InstantPageSourceLocation, anchor: String? = nil) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.webPage = webPage
self.anchor = anchor
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
super.init(navigationBarPresentationData: nil)
@ -145,7 +155,7 @@ public final class InstantPageController: ViewController {
}
override public func loadDisplayNode() {
self.displayNode = InstantPageControllerNode(controller: self, context: self.context, settings: self.settings, themeSettings: self.themeSettings, presentationTheme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, autoNightModeTriggered: self.presentationData.autoNightModeTriggered, statusBar: self.statusBar, sourcePeerType: self.sourcePeerType, getNavigationController: { [weak self] in
self.displayNode = InstantPageControllerNode(controller: self, context: self.context, settings: self.settings, themeSettings: self.themeSettings, presentationTheme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, autoNightModeTriggered: self.presentationData.autoNightModeTriggered, statusBar: self.statusBar, sourceLocation: self.sourceLocation, getNavigationController: { [weak self] in
return self?.navigationController as? NavigationController
}, present: { [weak self] c, a in
self?.present(c, in: .window(.root), with: a, blockInteraction: true)

View File

@ -29,7 +29,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
private let autoNightModeTriggered: Bool
private var dateTimeFormat: PresentationDateTimeFormat
private var theme: InstantPageTheme?
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private var manualThemeOverride: InstantPageThemeType?
private let getNavigationController: () -> NavigationController?
private let present: (ViewController, Any?) -> Void
@ -92,7 +92,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
return InstantPageStoredState(contentOffset: Double(self.scrollNode.view.contentOffset.y), details: details)
}
init(controller: InstantPageController, context: AccountContext, settings: InstantPagePresentationSettings?, themeSettings: PresentationThemeSettings?, presentationTheme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, autoNightModeTriggered: Bool, statusBar: StatusBar, sourcePeerType: MediaAutoDownloadPeerType, getNavigationController: @escaping () -> NavigationController?, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, openPeer: @escaping (EnginePeer) -> Void, navigateBack: @escaping () -> Void) {
init(controller: InstantPageController, context: AccountContext, settings: InstantPagePresentationSettings?, themeSettings: PresentationThemeSettings?, presentationTheme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, autoNightModeTriggered: Bool, statusBar: StatusBar, sourceLocation: InstantPageSourceLocation, getNavigationController: @escaping () -> NavigationController?, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, openPeer: @escaping (EnginePeer) -> Void, navigateBack: @escaping () -> Void) {
self.controller = controller
self.context = context
self.presentationTheme = presentationTheme
@ -106,7 +106,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.theme = settings.flatMap { settings in
return instantPageThemeForType(instantPageThemeTypeForSettingsAndTime(themeSettings: themeSettings, settings: settings, time: themeReferenceDate, forceDarkTheme: autoNightModeTriggered).0, settings: settings)
}
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.statusBar = statusBar
self.getNavigationController = getNavigationController
self.present = present
@ -445,7 +445,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
return
}
let currentLayout = instantPageLayoutForWebPage(webPage, boundingWidth: containerLayout.size.width, safeInset: containerLayout.safeInsets.left, strings: self.strings, theme: theme, dateTimeFormat: self.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights)
let currentLayout = instantPageLayoutForWebPage(webPage, userLocation: self.sourceLocation.userLocation, boundingWidth: containerLayout.size.width, safeInset: containerLayout.safeInsets.left, strings: self.strings, theme: theme, dateTimeFormat: self.dateTimeFormat, webEmbedHeights: self.currentWebEmbedHeights)
for (_, tileNode) in self.visibleTiles {
tileNode.removeFromSupernode()
@ -593,7 +593,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
let itemIndex = itemIndex
let embedIndex = embedIndex
let detailsIndex = detailsIndex
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourcePeerType: self.sourcePeerType, openMedia: { [weak self] media in
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourceLocation: self.sourceLocation, openMedia: { [weak self] media in
self?.openMedia(media)
}, longPressMedia: { [weak self] media in
self?.longPressMedia(media)
@ -1000,12 +1000,12 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: { [weak self] in
if let strongSelf = self, let image = media.media as? TelegramMediaImage {
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
let _ = copyToPasteboard(context: strongSelf.context, postbox: strongSelf.context.account.postbox, mediaReference: .standalone(media: media)).start()
let _ = copyToPasteboard(context: strongSelf.context, postbox: strongSelf.context.account.postbox, userLocation: strongSelf.sourceLocation.userLocation, mediaReference: .standalone(media: media)).start()
}
}), ContextMenuAction(content: .text(title: self.strings.Conversation_LinkDialogSave, accessibilityLabel: self.strings.Conversation_LinkDialogSave), action: { [weak self] in
if let strongSelf = self, let image = media.media as? TelegramMediaImage {
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
let _ = saveToCameraRoll(context: strongSelf.context, postbox: strongSelf.context.account.postbox, mediaReference: .standalone(media: media)).start()
let _ = saveToCameraRoll(context: strongSelf.context, postbox: strongSelf.context.account.postbox, userLocation: strongSelf.sourceLocation.userLocation, mediaReference: .standalone(media: media)).start()
}
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
if let strongSelf = self, let webPage = strongSelf.webPage, let image = media.media as? TelegramMediaImage {
@ -1211,7 +1211,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
return
}
let controller = InstantPageReferenceController(context: self.context, sourcePeerType: self.sourcePeerType, theme: theme, webPage: webPage, anchorText: anchorText, openUrl: { [weak self] url in
let controller = InstantPageReferenceController(context: self.context, sourceLocation: self.sourceLocation, theme: theme, webPage: webPage, anchorText: anchorText, openUrl: { [weak self] url in
self?.openUrl(url)
}, openUrlIn: { [weak self] url in
self?.openUrlIn(url)
@ -1310,7 +1310,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
case let .result(webpage):
if let webpage = webpage, case .Loaded = webpage.content {
strongSelf.loadProgress.set(1.0)
strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourcePeerType: strongSelf.sourcePeerType, anchor: anchor))
strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourceLocation: strongSelf.sourceLocation, anchor: anchor))
}
break
case let .progress(progress):
@ -1457,7 +1457,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
if let centralIndex = centralIndex {
let controller = InstantPageGalleryController(context: self.context, webPage: webPage, entries: entries, centralIndex: centralIndex, fromPlayingVideo: fromPlayingVideo, replaceRootController: { _, _ in
let controller = InstantPageGalleryController(context: self.context, userLocation: self.sourceLocation.userLocation, webPage: webPage, entries: entries, centralIndex: centralIndex, fromPlayingVideo: fromPlayingVideo, replaceRootController: { _, _ in
}, baseNavigationController: self.getNavigationController())
self.hiddenMediaDisposable.set((controller.hiddenMedia |> deliverOnMainQueue).start(next: { [weak self] entry in
if let strongSelf = self {

View File

@ -40,12 +40,12 @@ final class InstantPageDetailsItem: InstantPageItem {
self.index = index
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
var expanded: Bool?
if let expandedDetails = currentExpandedDetails, let currentlyExpanded = expandedDetails[self.index] {
expanded = currentlyExpanded
}
return InstantPageDetailsNode(context: context, sourcePeerType: sourcePeerType, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, item: self, openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl, currentlyExpanded: expanded, updateDetailsExpanded: updateDetailsExpanded)
return InstantPageDetailsNode(context: context, sourceLocation: sourceLocation, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, item: self, openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl, currentlyExpanded: expanded, updateDetailsExpanded: updateDetailsExpanded)
}
func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -35,7 +35,7 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
var requestLayoutUpdate: ((Bool) -> Void)?
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, item: InstantPageDetailsItem, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, currentlyExpanded: Bool?, updateDetailsExpanded: @escaping (Bool) -> Void) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, item: InstantPageDetailsItem, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, currentlyExpanded: Bool?, updateDetailsExpanded: @escaping (Bool) -> Void) {
self.context = context
self.strings = strings
self.nameDisplayOrder = nameDisplayOrder
@ -65,7 +65,7 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
self.arrowNode = InstantPageDetailsArrowNode(color: theme.controlColor, open: self.expanded)
self.separatorNode = ASDisplayNode()
self.contentNode = InstantPageContentNode(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, sourcePeerType: sourcePeerType, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height - item.titleHeight), openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl)
self.contentNode = InstantPageContentNode(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, sourceLocation: sourceLocation, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height - item.titleHeight), openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl)
super.init()

View File

@ -21,7 +21,7 @@ final class InstantPageFeedbackItem: InstantPageItem {
self.webPage = webPage
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageFeedbackNode(context: context, strings: strings, theme: theme, webPage: self.webPage, openUrl: openUrl)
}

View File

@ -48,7 +48,7 @@ public struct InstantPageGalleryEntry: Equatable {
return lhs.index == rhs.index && lhs.pageId == rhs.pageId && lhs.media == rhs.media && lhs.caption == rhs.caption && lhs.credit == rhs.credit && lhs.location == rhs.location
}
func item(context: AccountContext, webPage: TelegramMediaWebpage, message: Message?, presentationData: PresentationData, fromPlayingVideo: Bool, landscape: Bool, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) -> GalleryItem {
func item(context: AccountContext, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, message: Message?, presentationData: PresentationData, fromPlayingVideo: Bool, landscape: Bool, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) -> GalleryItem {
let caption: NSAttributedString
let credit: NSAttributedString
@ -97,7 +97,7 @@ public struct InstantPageGalleryEntry: Equatable {
}
if let image = self.media.media as? TelegramMediaImage {
return InstantImageGalleryItem(context: context, presentationData: presentationData, itemId: self.index, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: caption, credit: credit, location: self.location, openUrl: openUrl, openUrlOptions: openUrlOptions)
return InstantImageGalleryItem(context: context, presentationData: presentationData, itemId: self.index, userLocation: userLocation, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: caption, credit: credit, location: self.location, openUrl: openUrl, openUrlOptions: openUrlOptions)
} else if let file = self.media.media as? TelegramMediaFile {
if file.isVideo {
var indexData: GalleryItemIndexData?
@ -112,7 +112,7 @@ public struct InstantPageGalleryEntry: Equatable {
nativeId = .instantPage(self.pageId, file.fileId)
}
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file, nil), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, playbackRate: { nil }, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in })
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, userLocation: userLocation, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file, nil), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, playbackRate: { nil }, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in })
} else {
var representations: [TelegramMediaImageRepresentation] = []
representations.append(contentsOf: file.previewRepresentations)
@ -120,13 +120,13 @@ public struct InstantPageGalleryEntry: Equatable {
representations.append(TelegramMediaImageRepresentation(dimensions: dimensions, resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
}
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: file.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
return InstantImageGalleryItem(context: context, presentationData: presentationData, itemId: self.index, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: caption, credit: credit, location: self.location, openUrl: openUrl, openUrlOptions: openUrlOptions)
return InstantImageGalleryItem(context: context, presentationData: presentationData, itemId: self.index, userLocation: userLocation, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: caption, credit: credit, location: self.location, openUrl: openUrl, openUrlOptions: openUrlOptions)
}
} else if let embedWebpage = self.media.media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = embedWebpage.content {
if webpageContent.url.hasSuffix(".m3u8") {
let content = PlatformVideoContent(id: .instantPage(embedWebpage.webpageId, embedWebpage.webpageId), content: .url(webpageContent.url), streamVideo: true, loopVideo: false)
let content = PlatformVideoContent(id: .instantPage(embedWebpage.webpageId, embedWebpage.webpageId), userLocation: userLocation, content: .url(webpageContent.url), streamVideo: true, loopVideo: false)
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, { makeArguments, navigationController, present in
let gallery = InstantPageGalleryController(context: context, webPage: webPage, entries: [self], centralIndex: 0, replaceRootController: { [weak navigationController] controller, ready in
let gallery = InstantPageGalleryController(context: context, userLocation: userLocation, webPage: webPage, entries: [self], centralIndex: 0, replaceRootController: { [weak navigationController] controller, ready in
if let navigationController = navigationController {
navigationController.replaceTopController(controller, animated: false, ready: ready)
}
@ -136,7 +136,7 @@ public struct InstantPageGalleryEntry: Equatable {
}))
}), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, playbackRate: { nil }, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in })
} else {
if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent, openUrl: { url in
if let content = WebEmbedVideoContent(userLocation: userLocation, webPage: embedWebpage, webpageContent: webpageContent, openUrl: { url in
}) {
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, nil), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, playbackRate: { nil }, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in })
@ -164,6 +164,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
}
private let context: AccountContext
private let userLocation: MediaResourceUserLocation
private let webPage: TelegramMediaWebpage
private let message: Message?
private var presentationData: PresentationData
@ -201,8 +202,9 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
private var innerOpenUrl: (InstantPageUrlItem) -> Void
private var openUrlOptions: (InstantPageUrlItem) -> Void
public init(context: AccountContext, webPage: TelegramMediaWebpage, message: Message? = nil, entries: [InstantPageGalleryEntry], centralIndex: Int, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, baseNavigationController: NavigationController?) {
public init(context: AccountContext, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, message: Message? = nil, entries: [InstantPageGalleryEntry], centralIndex: Int, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, baseNavigationController: NavigationController?) {
self.context = context
self.userLocation = userLocation
self.webPage = webPage
self.message = message
self.fromPlayingVideo = fromPlayingVideo
@ -236,7 +238,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
strongSelf.centralEntryIndex = centralIndex
if strongSelf.isViewLoaded {
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
$0.item(context: context, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, landscape: landscape, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
$0.item(context: context, userLocation: userLocation, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, landscape: landscape, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
}), centralItemIndex: centralIndex)
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
@ -398,7 +400,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
}
self.galleryNode.pager.replaceItems(self.entries.map({
$0.item(context: self.context, webPage: self.webPage, message: self.message, presentationData: self.presentationData, fromPlayingVideo: self.fromPlayingVideo, landscape: self.landscape, openUrl: self.innerOpenUrl, openUrlOptions: self.openUrlOptions)
$0.item(context: self.context, userLocation: self.userLocation, webPage: self.webPage, message: self.message, presentationData: self.presentationData, fromPlayingVideo: self.fromPlayingVideo, landscape: self.landscape, openUrl: self.innerOpenUrl, openUrlOptions: self.openUrlOptions)
}), centralItemIndex: self.centralEntryIndex)
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in

View File

@ -45,8 +45,8 @@ final class InstantPageImageItem: InstantPageItem {
self.fit = fit
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageImageNode(context: context, sourcePeerType: sourcePeerType, theme: theme, webPage: self.webPage, media: self.media, attributes: self.attributes, interactive: self.interactive, roundCorners: self.roundCorners, fit: self.fit, openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished)
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageImageNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: self.webPage, media: self.media, attributes: self.attributes, interactive: self.interactive, roundCorners: self.roundCorners, fit: self.fit, openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished)
}
func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -49,7 +49,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
private var themeUpdated: Bool = false
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute], interactive: Bool, roundCorners: Bool, fit: Bool, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute], interactive: Bool, roundCorners: Bool, fit: Bool, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?) {
self.context = context
self.theme = theme
self.webPage = webPage
@ -74,15 +74,15 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
if let image = media.media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) {
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference))
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference))
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourcePeerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: sourceLocation.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
}
self.fetchControls = FetchControls(fetch: { [weak self] manual in
if let strongSelf = self {
strongSelf.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
strongSelf.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: sourceLocation.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
}
}, cancel: {
chatMessagePhotoCancelInteractiveFetch(account: context.account, photoReference: imageReference)
@ -108,12 +108,12 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
} else if let file = media.media as? TelegramMediaFile {
let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file)
if file.mimeType.hasPrefix("image/") {
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourcePeerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
_ = freeMediaFileInteractiveFetched(account: context.account, fileReference: fileReference).start()
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
_ = freeMediaFileInteractiveFetched(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference).start()
}
self.imageNode.setSignal(instantPageImageFile(account: context.account, fileReference: fileReference, fetched: true))
self.imageNode.setSignal(instantPageImageFile(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference, fetched: true))
} else {
self.imageNode.setSignal(chatMessageVideo(postbox: context.account.postbox, videoReference: fileReference))
self.imageNode.setSignal(chatMessageVideo(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, videoReference: fileReference))
}
if file.isVideo {
self.statusNode.transitionToState(.play(.white), animated: false, completion: {})
@ -133,8 +133,8 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
self.imageNode.setSignal(chatMapSnapshotImage(engine: context.engine, resource: resource))
} else if let webPage = media.media as? TelegramMediaWebpage, case let .Loaded(content) = webPage.content, let image = content.image {
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference))
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference))
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: sourceLocation.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerType: nil).start())
self.statusNode.transitionToState(.play(.white), animated: false, completion: {})
self.pinchContainerNode.contentNode.addSubnode(self.statusNode)
}

View File

@ -16,7 +16,7 @@ protocol InstantPageItem {
func matchesAnchor(_ anchor: String) -> Bool
func drawInTile(context: CGContext)
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode?
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode?
func matchesNode(_ node: InstantPageNode) -> Bool
func linkSelectionRects(at point: CGPoint) -> [CGRect]

View File

@ -48,7 +48,7 @@ private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantP
}
}
func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToSize: CGSize?, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, detailsIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:], excludeCaptions: Bool) -> InstantPageLayout {
func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation: MediaResourceUserLocation, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToSize: CGSize?, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, detailsIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:], excludeCaptions: Bool) -> InstantPageLayout {
let layoutCaption: (InstantPageCaption, CGSize) -> ([InstantPageItem], CGSize) = { caption, contentSize in
var items: [InstantPageItem] = []
@ -101,7 +101,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
switch block {
case let .cover(block):
return layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToSize: fillToSize, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
return layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToSize: fillToSize, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
case let .title(text):
let styleStack = InstantPageTextStyleStack()
setupStyleStack(styleStack, theme: theme, category: .header, link: false)
@ -275,7 +275,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
var previousBlock: InstantPageBlock?
var originY: CGFloat = contentSize.height
for subBlock in blocks {
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let spacing: CGFloat = previousBlock != nil && subLayout.contentSize.height > 0.0 ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing))
@ -477,7 +477,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
var i = 0
for subItem in innerItems {
let frame = mosaicLayout[i].0
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subItem, boundingWidth: frame.width, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: frame.size, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: true)
let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subItem, boundingWidth: frame.width, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: frame.size, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: true)
items.append(contentsOf: subLayout.flattenedItemsWithOrigin(frame.origin))
i += 1
}
@ -545,7 +545,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
var previousBlock: InstantPageBlock?
for subBlock in blocks {
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + lineInset, y: contentSize.height + spacing))
@ -728,7 +728,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
var previousBlock: InstantPageBlock?
for subBlock in blocks {
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: false, previousItems: subitems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &subDetailsIndex, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let subLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: subBlock, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: false, previousItems: subitems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &subDetailsIndex, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing))
@ -791,7 +791,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
}
let description = attributedStringForRichText(.plain(subtext ?? ""), styleStack: styleStack)
let item = layoutArticleItem(theme: theme, webPage: webpage, title: title, description: description, cover: cover, url: article.url, webpageId: article.webpageId, boundingWidth: boundingWidth, rtl: rtl)
let item = layoutArticleItem(theme: theme, userLocation: userLocation, webPage: webpage, title: title, description: description, cover: cover, url: article.url, webpageId: article.webpageId, boundingWidth: boundingWidth, rtl: rtl)
item.frame = item.frame.offsetBy(dx: 0.0, dy: contentSize.height)
contentSize.height += item.frame.height
items.append(item)
@ -835,7 +835,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
}
}
func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:]) -> InstantPageLayout {
func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, userLocation: MediaResourceUserLocation, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:]) -> InstantPageLayout {
var maybeLoadedContent: TelegramMediaWebpageLoadedContent?
if case let .Loaded(content) = webPage.content {
maybeLoadedContent = content
@ -864,7 +864,7 @@ func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth:
var previousBlock: InstantPageBlock?
for block in pageBlocks {
let blockLayout = layoutInstantPageBlock(webpage: webPage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let blockLayout = layoutInstantPageBlock(webpage: webPage, userLocation: userLocation, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, excludeCaptions: false)
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: block)
let blockItems = blockLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing))
items.append(contentsOf: blockItems)

View File

@ -27,7 +27,7 @@ final class InstantPagePeerReferenceItem: InstantPageItem {
self.rtl = rtl
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPagePeerReferenceNode(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, initialPeer: self.initialPeer, safeInset: self.safeInset, transparent: self.transparent, rtl: self.rtl, openPeer: openPeer)
}

View File

@ -29,8 +29,8 @@ final class InstantPagePlayableVideoItem: InstantPageItem {
self.interactive = interactive
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPagePlayableVideoNode(context: context, webPage: self.webPage, theme: theme, media: self.media, interactive: self.interactive, openMedia: openMedia)
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPagePlayableVideoNode(context: context, userLocation: sourceLocation.userLocation, webPage: self.webPage, theme: theme, media: self.media, interactive: self.interactive, openMedia: openMedia)
}
func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -19,6 +19,7 @@ private struct FetchControls {
final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, GalleryItemTransitionNode {
private let context: AccountContext
let media: InstantPageMedia
let userLocation: MediaResourceUserLocation
private let interactive: Bool
private let openMedia: (InstantPageMedia) -> Void
private var fetchControls: FetchControls?
@ -38,8 +39,9 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, Galler
return nil
}
init(context: AccountContext, webPage: TelegramMediaWebpage, theme: InstantPageTheme, media: InstantPageMedia, interactive: Bool, openMedia: @escaping (InstantPageMedia) -> Void) {
init(context: AccountContext, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, theme: InstantPageTheme, media: InstantPageMedia, interactive: Bool, openMedia: @escaping (InstantPageMedia) -> Void) {
self.context = context
self.userLocation = userLocation
self.media = media
self.interactive = interactive
self.openMedia = openMedia
@ -55,7 +57,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, Galler
streamVideo = isMediaStreamable(media: file)
}
self.videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: NativeVideoContent(id: .instantPage(webPage.webpageId, media.media.id!), fileReference: .webPage(webPage: WebpageReference(webPage), media: media.media as! TelegramMediaFile), imageReference: imageReference, streamVideo: streamVideo ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, placeholderColor: theme.pageBackgroundColor), priority: .embedded, autoplay: true)
self.videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: NativeVideoContent(id: .instantPage(webPage.webpageId, media.media.id!), userLocation: userLocation, fileReference: .webPage(webPage: WebpageReference(webPage), media: media.media as! TelegramMediaFile), imageReference: imageReference, streamVideo: streamVideo ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, placeholderColor: theme.pageBackgroundColor), priority: .embedded, autoplay: true)
self.videoNode.isUserInteractionEnabled = false
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
@ -65,7 +67,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, Galler
self.addSubnode(self.videoNode)
if let file = media.media as? TelegramMediaFile {
self.fetchedDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: AnyMediaReference.webPage(webPage: WebpageReference(webPage), media: file).resourceReference(file.resource)).start())
self.fetchedDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .video, reference: AnyMediaReference.webPage(webPage: WebpageReference(webPage), media: file).resourceReference(file.resource)).start())
self.statusDisposable.set((context.account.postbox.mediaBox.resourceStatus(file.resource) |> deliverOnMainQueue).start(next: { [weak self] status in
displayLinkDispatcher.dispatch {

View File

@ -16,7 +16,7 @@ final class InstantPageReferenceController: ViewController {
private var animatedIn = false
private let context: AccountContext
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let theme: InstantPageTheme
private let webPage: TelegramMediaWebpage
private let anchorText: NSAttributedString
@ -24,9 +24,9 @@ final class InstantPageReferenceController: ViewController {
private let openUrlIn: (InstantPageUrlItem) -> Void
private let present: (ViewController, Any?) -> Void
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, webPage: TelegramMediaWebpage, anchorText: NSAttributedString, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlIn: @escaping (InstantPageUrlItem) -> Void, present: @escaping (ViewController, Any?) -> Void) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, anchorText: NSAttributedString, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlIn: @escaping (InstantPageUrlItem) -> Void, present: @escaping (ViewController, Any?) -> Void) {
self.context = context
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.theme = theme
self.webPage = webPage
self.anchorText = anchorText
@ -44,7 +44,7 @@ final class InstantPageReferenceController: ViewController {
}
override public func loadDisplayNode() {
self.displayNode = InstantPageReferenceControllerNode(context: self.context, sourcePeerType: self.sourcePeerType, theme: self.theme, webPage: self.webPage, anchorText: self.anchorText, openUrl: self.openUrl, openUrlIn: self.openUrlIn, present: self.present)
self.displayNode = InstantPageReferenceControllerNode(context: self.context, sourceLocation: self.sourceLocation, theme: self.theme, webPage: self.webPage, anchorText: self.anchorText, openUrl: self.openUrl, openUrlIn: self.openUrlIn, present: self.present)
self.controllerNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}

View File

@ -13,7 +13,7 @@ import TelegramUIPreferences
class InstantPageReferenceControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let context: AccountContext
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let theme: InstantPageTheme
private var presentationData: PresentationData
private let webPage: TelegramMediaWebpage
@ -39,9 +39,9 @@ class InstantPageReferenceControllerNode: ViewControllerTracingNode, UIScrollVie
var dismiss: (() -> Void)?
var close: (() -> Void)?
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, webPage: TelegramMediaWebpage, anchorText: NSAttributedString, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlIn: @escaping (InstantPageUrlItem) -> Void, present: @escaping (ViewController, Any?) -> Void) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, anchorText: NSAttributedString, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlIn: @escaping (InstantPageUrlItem) -> Void, present: @escaping (ViewController, Any?) -> Void) {
self.context = context
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.theme = theme
self.webPage = webPage
@ -204,7 +204,7 @@ class InstantPageReferenceControllerNode: ViewControllerTracingNode, UIScrollVie
let sideInset: CGFloat = 16.0
let (_, items, contentSize) = layoutTextItemWithString(self.anchorText, boundingWidth: width - sideInset * 2.0, offset: CGPoint(x: sideInset, y: sideInset), media: media, webpage: self.webPage)
let contentNode = InstantPageContentNode(context: self.context, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, sourcePeerType: self.sourcePeerType, theme: self.theme, items: items, contentSize: CGSize(width: width, height: contentSize.height), inOverlayPanel: true, openMedia: { _ in }, longPressMedia: { _ in }, openPeer: { _ in }, openUrl: { _ in })
let contentNode = InstantPageContentNode(context: self.context, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, sourceLocation: self.sourceLocation, theme: self.theme, items: items, contentSize: CGSize(width: width, height: contentSize.height), inOverlayPanel: true, openMedia: { _ in }, longPressMedia: { _ in }, openPeer: { _ in }, openUrl: { _ in })
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: titleAreaHeight), size: CGSize(width: width, height: contentSize.height)))
self.contentContainerNode.insertSubnode(contentNode, at: 0)
self.contentNode = contentNode

View File

@ -62,7 +62,7 @@ final class InstantPageShapeItem: InstantPageItem {
return false
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return nil
}

View File

@ -21,8 +21,8 @@ final class InstantPageSlideshowItem: InstantPageItem {
self.medias = medias
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageSlideshowNode(context: context, sourcePeerType: sourcePeerType, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia, longPressMedia: longPressMedia)
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageSlideshowNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia, longPressMedia: longPressMedia)
}
func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -64,7 +64,7 @@ private final class InstantPageSlideshowItemNode: ASDisplayNode {
private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDelegate {
private let context: AccountContext
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let theme: InstantPageTheme
private let webPage: TelegramMediaWebpage
private let openMedia: (InstantPageMedia) -> Void
@ -98,9 +98,9 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDe
}
}
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, webPage: TelegramMediaWebpage, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, pageGap: CGFloat = 0.0) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, pageGap: CGFloat = 0.0) {
self.context = context
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.theme = theme
self.webPage = webPage
self.openMedia = openMedia
@ -182,7 +182,7 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDe
let media = self.items[index]
let contentNode: ASDisplayNode
if let _ = media.media as? TelegramMediaImage {
contentNode = InstantPageImageNode(context: self.context, sourcePeerType: self.sourcePeerType, theme: self.theme, webPage: self.webPage, media: media, attributes: [], interactive: true, roundCorners: false, fit: false, openMedia: self.openMedia, longPressMedia: self.longPressMedia, activatePinchPreview: nil, pinchPreviewFinished: nil)
contentNode = InstantPageImageNode(context: self.context, sourceLocation: self.sourceLocation, theme: self.theme, webPage: self.webPage, media: media, attributes: [], interactive: true, roundCorners: false, fit: false, openMedia: self.openMedia, longPressMedia: self.longPressMedia, activatePinchPreview: nil, pinchPreviewFinished: nil)
} else if let _ = media.media as? TelegramMediaFile {
contentNode = ASDisplayNode()
} else {
@ -381,10 +381,10 @@ final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode {
private let pagerNode: InstantPageSlideshowPagerNode
private let pageControlNode: PageControlNode
init(context: AccountContext, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, webPage: TelegramMediaWebpage, medias: [InstantPageMedia], openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void) {
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, medias: [InstantPageMedia], openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void) {
self.medias = medias
self.pagerNode = InstantPageSlideshowPagerNode(context: context, sourcePeerType: sourcePeerType, theme: theme, webPage: webPage, openMedia: openMedia, longPressMedia: longPressMedia)
self.pagerNode = InstantPageSlideshowPagerNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, openMedia: openMedia, longPressMedia: longPressMedia)
self.pagerNode.replaceItems(medias, centralItemIndex: nil)
self.pageControlNode = PageControlNode(dotColor: .white, inactiveDotColor: UIColor(white: 1.0, alpha: 0.5))

View File

@ -13,7 +13,7 @@ final class InstantPageSubContentNode : ASDisplayNode {
private let context: AccountContext
private let strings: PresentationStrings
private let nameDisplayOrder: PresentationPersonNameOrder
private let sourcePeerType: MediaAutoDownloadPeerType
private let sourceLocation: InstantPageSourceLocation
private let theme: InstantPageTheme
private let openMedia: (InstantPageMedia) -> Void
@ -40,11 +40,11 @@ final class InstantPageSubContentNode : ASDisplayNode {
private var previousVisibleBounds: CGRect?
init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourcePeerType: MediaAutoDownloadPeerType, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) {
init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) {
self.context = context
self.strings = strings
self.nameDisplayOrder = nameDisplayOrder
self.sourcePeerType = sourcePeerType
self.sourceLocation = sourceLocation
self.theme = theme
self.openMedia = openMedia
@ -188,7 +188,7 @@ final class InstantPageSubContentNode : ASDisplayNode {
if itemNode == nil {
let itemIndex = itemIndex
let detailsIndex = detailsIndex
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourcePeerType: self.sourcePeerType, openMedia: { [weak self] media in
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourceLocation: self.sourceLocation, openMedia: { [weak self] media in
self?.openMedia(media)
}, longPressMedia: { [weak self] media in
self?.longPressMedia(media)

View File

@ -200,12 +200,12 @@ final class InstantPageTableItem: InstantPageScrollableItem {
return false
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
var additionalNodes: [InstantPageNode] = []
for cell in self.cells {
for item in cell.additionalItems {
if item.wantsNode {
if let node = item.node(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, sourcePeerType: sourcePeerType, openMedia: { _ in }, longPressMedia: { _ in }, activatePinchPreview: nil, pinchPreviewFinished: nil, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _ in }, updateDetailsExpanded: { _ in }, currentExpandedDetails: nil) {
if let node = item.node(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, sourceLocation: sourceLocation, openMedia: { _ in }, longPressMedia: { _ in }, activatePinchPreview: nil, pinchPreviewFinished: nil, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _ in }, updateDetailsExpanded: { _ in }, currentExpandedDetails: nil) {
node.frame = item.frame.offsetBy(dx: cell.frame.minX, dy: cell.frame.minY)
additionalNodes.append(node)
}

View File

@ -436,7 +436,7 @@ final class InstantPageTextItem: InstantPageItem {
return false
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return nil
}
@ -485,11 +485,11 @@ final class InstantPageScrollableTextItem: InstantPageScrollableItem {
context.restoreGState()
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
var additionalNodes: [InstantPageNode] = []
for item in additionalItems {
if item.wantsNode {
if let node = item.node(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, sourcePeerType: sourcePeerType, openMedia: { _ in }, longPressMedia: { _ in }, activatePinchPreview: nil, pinchPreviewFinished: nil, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _ in }, updateDetailsExpanded: { _ in }, currentExpandedDetails: nil) {
if let node = item.node(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, sourceLocation: sourceLocation, openMedia: { _ in }, longPressMedia: { _ in }, activatePinchPreview: nil, pinchPreviewFinished: nil, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _ in }, updateDetailsExpanded: { _ in }, currentExpandedDetails: nil) {
node.frame = item.frame
additionalNodes.append(node)
}

View File

@ -25,7 +25,7 @@ final class InstantPageWebEmbedItem: InstantPageItem {
self.enableScrolling = enableScrolling
}
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourcePeerType: MediaAutoDownloadPeerType, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageWebEmbedNode(frame: self.frame, url: self.url, html: self.html, enableScrolling: self.enableScrolling, updateWebEmbedHeight: updateWebEmbedHeight)
}

View File

@ -517,7 +517,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
}
}
if fileUpdated, let resourceReference = resourceReference {
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, reference: resourceReference)
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference)
}
} else {
updatedImageSignal = .single({ _ in return nil })

View File

@ -59,7 +59,7 @@ public enum LegacyAttachmentMenuMediaEditing {
}
public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle: String?, media: AnyMediaReference, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) {
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: media)
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media)
|> deliverOnMainQueue).start(next: { (value, isImage) in
guard case let .data(data) = value, data.complete else {
return
@ -341,7 +341,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, threadTitl
let editCurrentItem = TGMenuSheetButtonItemView(title: title, type: TGMenuSheetButtonTypeDefault, fontSize: fontSize, action: { [weak controller] in
controller?.dismiss(animated: true)
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: editCurrentMedia)
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: editCurrentMedia)
|> deliverOnMainQueue).start(next: { (value, isImage) in
guard case let .data(data) = value, data.complete else {
return

View File

@ -54,7 +54,7 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
public func legacyAvatarEditor(context: AccountContext, media: AnyMediaReference, transitionView: UIView?, present: @escaping (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments) -> Void) {
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: media)
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media)
|> deliverOnMainQueue).start(next: { (value, isImage) in
guard case let .data(data) = value, data.complete else {
return

View File

@ -79,8 +79,8 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView {
self.addSubnode(animationNode)
}
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start())
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start())
} else {
if let animationNode = self.animationNode {
animationNode.visibility = false
@ -89,8 +89,8 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView {
self.imageNode.isHidden = false
self.didSetUpAnimationNode = false
}
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, file: self.file, small: false, synchronousLoad: false))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start())
self.imageNode.setSignal(chatMessageSticker(account: self.context.account, userLocation: .other, file: self.file, small: false, synchronousLoad: false))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start())
}
self.dimensions = dimensions.cgSize

View File

@ -128,7 +128,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
}))
}
} else {
self.disposables.add((chatMessageSticker(account: self.account, file: self.file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
self.disposables.add((chatMessageSticker(account: self.account, userLocation: .other, file: self.file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
|> deliverOn(self.queue)).start(next: { [weak self] generator in
if let strongSelf = self {
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: entity.baseSize, boundingSize: entity.baseSize, intrinsicInsets: UIEdgeInsets()))

View File

@ -1005,16 +1005,16 @@ public final class ListMessageFileItemNode: ListMessageNode {
switch iconImage {
case let .imageRepresentation(media, representation):
if let file = media as? TelegramMediaFile {
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, mediaReference: FileMediaReference.message(message: MessageReference(message), media: file).abstract, representation: representation)
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, userLocation: .peer(message.id.peerId), mediaReference: FileMediaReference.message(message: MessageReference(message), media: file).abstract, representation: representation)
} else if let image = media as? TelegramMediaImage {
updateIconImageSignal = mediaGridMessagePhoto(account: item.context.account, photoReference: ImageMediaReference.message(message: MessageReference(message), media: image))
updateIconImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(message.id.peerId), photoReference: ImageMediaReference.message(message: MessageReference(message), media: image))
} else {
updateIconImageSignal = .complete()
}
case let .albumArt(file, albumArt):
updateIconImageSignal = playerAlbumArt(postbox: item.context.account.postbox, engine: item.context.engine, fileReference: .message(message: MessageReference(message), media: file), albumArt: albumArt, thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), emptyColor: item.presentationData.theme.theme.list.itemAccentColor)
case let .roundVideo(file):
updateIconImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, videoReference: FileMediaReference.message(message: MessageReference(message), media: file), autoFetchFullSizeThumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3))
updateIconImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: FileMediaReference.message(message: MessageReference(message), media: file), autoFetchFullSizeThumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3))
}
} else {
updateIconImageSignal = .complete()

View File

@ -578,9 +578,9 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
updateIconImageSignal = wallpaperThumbnail(account: item.context.account, accountManager: item.context.sharedContext.accountManager, fileReference: fileReference, wallpaper: previewWallpaper, synchronousLoad: false)
} else if let iconImageReferenceAndRepresentation = iconImageReferenceAndRepresentation {
if let imageReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaImage.self) {
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.context.account, photoReference: imageReference)
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.context.account, userLocation: (item.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, photoReference: imageReference)
} else if let fileReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaFile.self) {
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, mediaReference: fileReference.abstract, representation: iconImageReferenceAndRepresentation.1)
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, userLocation: (item.message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, mediaReference: fileReference.abstract, representation: iconImageReferenceAndRepresentation.1)
}
} else {
updateIconImageSignal = .complete()

View File

@ -68,6 +68,8 @@ private func contextForCurrentThread() -> FFMpegMediaFrameSourceContext? {
public final class FFMpegMediaFrameSource: NSObject, MediaFrameSource {
private let queue: Queue
private let postbox: Postbox
private let userLocation: MediaResourceUserLocation
private let userContentType: MediaResourceUserContentType
private let resourceReference: MediaResourceReference
private let tempFilePath: String?
private let streamable: Bool
@ -98,9 +100,11 @@ public final class FFMpegMediaFrameSource: NSObject, MediaFrameSource {
}
}
public init(queue: Queue, postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int? = nil, stallDuration: Double = 1.0, lowWaterDuration: Double = 2.0, highWaterDuration: Double = 3.0) {
public init(queue: Queue, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int? = nil, stallDuration: Double = 1.0, lowWaterDuration: Double = 2.0, highWaterDuration: Double = 3.0) {
self.queue = queue
self.postbox = postbox
self.userLocation = userLocation
self.userContentType = userContentType
self.resourceReference = resourceReference
self.tempFilePath = tempFilePath
self.streamable = streamable
@ -181,13 +185,14 @@ public final class FFMpegMediaFrameSource: NSObject, MediaFrameSource {
let tempFilePath = self.tempFilePath
let queue = self.queue
let streamable = self.streamable
let userLocation = self.userLocation
let video = self.video
let preferSoftwareDecoding = self.preferSoftwareDecoding
let fetchAutomatically = self.fetchAutomatically
let maximumFetchSize = self.maximumFetchSize
self.performWithContext { [weak self] context in
context.initializeState(postbox: postbox, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, fetchAutomatically: fetchAutomatically, maximumFetchSize: maximumFetchSize)
context.initializeState(postbox: postbox, userLocation: userLocation, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, fetchAutomatically: fetchAutomatically, maximumFetchSize: maximumFetchSize)
let (frames, endOfStream) = context.takeFrames(until: timestamp)
@ -228,6 +233,7 @@ public final class FFMpegMediaFrameSource: NSObject, MediaFrameSource {
let queue = self.queue
let postbox = self.postbox
let userLocation = self.userLocation
let resourceReference = self.resourceReference
let tempFilePath = self.tempFilePath
let streamable = self.streamable
@ -245,7 +251,7 @@ public final class FFMpegMediaFrameSource: NSObject, MediaFrameSource {
self.performWithContext { [weak self] context in
let _ = currentSemaphore.swap(context.currentSemaphore)
context.initializeState(postbox: postbox, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, fetchAutomatically: fetchAutomatically, maximumFetchSize: maximumFetchSize)
context.initializeState(postbox: postbox, userLocation: userLocation, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, fetchAutomatically: fetchAutomatically, maximumFetchSize: maximumFetchSize)
context.seek(timestamp: timestamp, completed: { streamDescriptionsAndTimestamp in
queue.async {

View File

@ -196,7 +196,7 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa
private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whence: Int32) -> Int64 {
let context = Unmanaged<FFMpegMediaFrameSourceContext>.fromOpaque(userData!).takeUnretainedValue()
guard let postbox = context.postbox, let resourceReference = context.resourceReference, let streamable = context.streamable, let statsCategory = context.statsCategory else {
guard let postbox = context.postbox, let resourceReference = context.resourceReference, let streamable = context.streamable, let userLocation = context.userLocation, let userContentType = context.userContentType, let statsCategory = context.statsCategory else {
return 0
}
@ -250,12 +250,12 @@ private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whe
if streamable {
if context.tempFilePath == nil {
let fetchRange: Range<Int64> = context.readingOffset ..< Int64.max
context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (fetchRange, .elevated), statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start())
context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: resourceReference, range: (fetchRange, .elevated), statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start())
}
} else if !context.requestedCompleteFetch && context.fetchAutomatically {
context.requestedCompleteFetch = true
if context.tempFilePath == nil {
context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start())
context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: resourceReference, statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start())
}
}
}
@ -276,6 +276,8 @@ final class FFMpegMediaFrameSourceContext: NSObject {
var closed = false
fileprivate var postbox: Postbox?
fileprivate var userLocation: MediaResourceUserLocation?
fileprivate var userContentType: MediaResourceUserContentType?
fileprivate var resourceReference: MediaResourceReference?
fileprivate var tempFilePath: String?
fileprivate var streamable: Bool?
@ -320,7 +322,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
self.keepDataDisposable.dispose()
}
func initializeState(postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int?) {
func initializeState(postbox: Postbox, userLocation: MediaResourceUserLocation, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int?) {
if self.readingError || self.initializedState != nil {
return
}
@ -332,6 +334,8 @@ final class FFMpegMediaFrameSourceContext: NSObject {
self.tempFilePath = tempFilePath
self.streamable = streamable
self.statsCategory = video ? .video : .audio
self.userLocation = userLocation
self.userContentType = video ? .video : .audio
self.preferSoftwareDecoding = preferSoftwareDecoding
self.fetchAutomatically = fetchAutomatically
self.maximumFetchSize = maximumFetchSize
@ -342,12 +346,12 @@ final class FFMpegMediaFrameSourceContext: NSObject {
if streamable {
if self.tempFilePath == nil {
self.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int64.max, .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
self.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: self.userLocation ?? .other, userContentType: self.userContentType ?? .other, reference: resourceReference, range: (0 ..< Int64.max, .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
}
} else if !self.requestedCompleteFetch && self.fetchAutomatically {
self.requestedCompleteFetch = true
if self.tempFilePath == nil {
self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: self.userLocation ?? .other, userContentType: self.userContentType ?? .other, reference: resourceReference, statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
}
}
@ -449,7 +453,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
if streamable {
if self.tempFilePath == nil {
self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int64.max, .default), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: self.userLocation ?? .other, userContentType: self.userContentType ?? .other, reference: resourceReference, range: (0 ..< Int64.max, .default), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
}
self.requestedCompleteFetch = true
}

View File

@ -101,6 +101,8 @@ private final class MediaPlayerContext {
private let audioSessionManager: ManagedAudioSession
private let postbox: Postbox
private let userLocation: MediaResourceUserLocation
private let userContentType: MediaResourceUserContentType
private let resourceReference: MediaResourceReference
private let tempFilePath: String?
private let streamable: MediaPlayerStreaming
@ -133,7 +135,7 @@ private final class MediaPlayerContext {
private var stoppedAtEnd = false
init(queue: Queue, audioSessionManager: ManagedAudioSession, playerStatus: Promise<MediaPlayerStatus>, audioLevelPipe: ValuePipe<Float>, postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: MediaPlayerStreaming, video: Bool, preferSoftwareDecoding: Bool, playAutomatically: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, playAndRecord: Bool, ambient: Bool, keepAudioSessionWhilePaused: Bool, continuePlayingWithoutSoundOnLostAudioSession: Bool) {
init(queue: Queue, audioSessionManager: ManagedAudioSession, playerStatus: Promise<MediaPlayerStatus>, audioLevelPipe: ValuePipe<Float>, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: MediaPlayerStreaming, video: Bool, preferSoftwareDecoding: Bool, playAutomatically: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, playAndRecord: Bool, ambient: Bool, keepAudioSessionWhilePaused: Bool, continuePlayingWithoutSoundOnLostAudioSession: Bool) {
assert(queue.isCurrent())
self.queue = queue
@ -141,6 +143,8 @@ private final class MediaPlayerContext {
self.playerStatus = playerStatus
self.audioLevelPipe = audioLevelPipe
self.postbox = postbox
self.userLocation = userLocation
self.userContentType = userContentType
self.resourceReference = resourceReference
self.tempFilePath = tempFilePath
self.streamable = streamable
@ -300,7 +304,7 @@ private final class MediaPlayerContext {
let _ = self.playerStatusValue.swap(status)
}
let frameSource = FFMpegMediaFrameSource(queue: self.queue, postbox: self.postbox, resourceReference: self.resourceReference, tempFilePath: self.tempFilePath, streamable: self.streamable.enabled, video: self.video, preferSoftwareDecoding: self.preferSoftwareDecoding, fetchAutomatically: self.fetchAutomatically, stallDuration: self.streamable.parameters.0, lowWaterDuration: self.streamable.parameters.1, highWaterDuration: self.streamable.parameters.2)
let frameSource = FFMpegMediaFrameSource(queue: self.queue, postbox: self.postbox, userLocation: self.userLocation, userContentType: self.userContentType, resourceReference: self.resourceReference, tempFilePath: self.tempFilePath, streamable: self.streamable.enabled, video: self.video, preferSoftwareDecoding: self.preferSoftwareDecoding, fetchAutomatically: self.fetchAutomatically, stallDuration: self.streamable.parameters.0, lowWaterDuration: self.streamable.parameters.1, highWaterDuration: self.streamable.parameters.2)
let disposable = MetaDisposable()
let updatedSeekState: MediaPlayerSeekState?
if let loadedDuration = loadedDuration {
@ -1061,10 +1065,10 @@ public final class MediaPlayer {
}
}
public init(audioSessionManager: ManagedAudioSession, postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String? = nil, streamable: MediaPlayerStreaming, video: Bool, preferSoftwareDecoding: Bool, playAutomatically: Bool = false, enableSound: Bool, baseRate: Double = 1.0, fetchAutomatically: Bool, playAndRecord: Bool = false, ambient: Bool = false, keepAudioSessionWhilePaused: Bool = false, continuePlayingWithoutSoundOnLostAudioSession: Bool = false) {
public init(audioSessionManager: ManagedAudioSession, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resourceReference: MediaResourceReference, tempFilePath: String? = nil, streamable: MediaPlayerStreaming, video: Bool, preferSoftwareDecoding: Bool, playAutomatically: Bool = false, enableSound: Bool, baseRate: Double = 1.0, fetchAutomatically: Bool, playAndRecord: Bool = false, ambient: Bool = false, keepAudioSessionWhilePaused: Bool = false, continuePlayingWithoutSoundOnLostAudioSession: Bool = false) {
let audioLevelPipe = self.audioLevelPipe
self.queue.async {
let context = MediaPlayerContext(queue: self.queue, audioSessionManager: audioSessionManager, playerStatus: self.statusValue, audioLevelPipe: audioLevelPipe, postbox: postbox, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, playAutomatically: playAutomatically, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, playAndRecord: playAndRecord, ambient: ambient, keepAudioSessionWhilePaused: keepAudioSessionWhilePaused, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession)
let context = MediaPlayerContext(queue: self.queue, audioSessionManager: audioSessionManager, playerStatus: self.statusValue, audioLevelPipe: audioLevelPipe, postbox: postbox, userLocation: userLocation, userContentType: userContentType, resourceReference: resourceReference, tempFilePath: tempFilePath, streamable: streamable, video: video, preferSoftwareDecoding: preferSoftwareDecoding, playAutomatically: playAutomatically, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, playAndRecord: playAndRecord, ambient: ambient, keepAudioSessionWhilePaused: keepAudioSessionWhilePaused, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession)
self.contextRef = Unmanaged.passRetained(context)
}
}

View File

@ -25,9 +25,9 @@ private final class FramePreviewContext {
}
}
private func initializedPreviewContext(queue: Queue, postbox: Postbox, fileReference: FileMediaReference) -> Signal<QueueLocalObject<FramePreviewContext>, NoError> {
private func initializedPreviewContext(queue: Queue, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference) -> Signal<QueueLocalObject<FramePreviewContext>, NoError> {
return Signal { subscriber in
let source = UniversalSoftwareVideoSource(mediaBox: postbox.mediaBox, fileReference: fileReference)
let source = UniversalSoftwareVideoSource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, fileReference: fileReference)
let readyDisposable = (source.ready
|> filter { $0 }).start(next: { _ in
subscriber.putNext(QueueLocalObject(queue: queue, generate: {
@ -49,10 +49,10 @@ private final class MediaPlayerFramePreviewImpl {
private var nextFrameTimestamp: Double?
fileprivate let framePipe = ValuePipe<FramePreviewResult>()
init(queue: Queue, postbox: Postbox, fileReference: FileMediaReference) {
init(queue: Queue, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference) {
self.queue = queue
self.context = Promise()
self.context.set(initializedPreviewContext(queue: queue, postbox: postbox, fileReference: fileReference))
self.context.set(initializedPreviewContext(queue: queue, postbox: postbox, userLocation: userLocation, userContentType: userContentType, fileReference: fileReference))
}
deinit {
@ -131,11 +131,11 @@ public final class MediaPlayerFramePreview: FramePreview {
}
}
public init(postbox: Postbox, fileReference: FileMediaReference) {
public init(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference) {
let queue = Queue()
self.queue = queue
self.impl = QueueLocalObject(queue: queue, generate: {
return MediaPlayerFramePreviewImpl(queue: queue, postbox: postbox, fileReference: fileReference)
return MediaPlayerFramePreviewImpl(queue: queue, postbox: postbox, userLocation: userLocation, userContentType: userContentType, fileReference: fileReference)
})
}

View File

@ -5,14 +5,14 @@ import Postbox
import TelegramCore
import FFMpegBinding
public func preloadVideoResource(postbox: Postbox, resourceReference: MediaResourceReference, duration: Double) -> Signal<Never, NoError> {
public func preloadVideoResource(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resourceReference: MediaResourceReference, duration: Double) -> Signal<Never, NoError> {
return Signal { subscriber in
let queue = Queue()
let disposable = MetaDisposable()
queue.async {
let maximumFetchSize = 2 * 1024 * 1024 + 128 * 1024
//let maximumFetchSize = 128
let sourceImpl = FFMpegMediaFrameSource(queue: queue, postbox: postbox, resourceReference: resourceReference, tempFilePath: nil, streamable: true, video: true, preferSoftwareDecoding: false, fetchAutomatically: true, maximumFetchSize: maximumFetchSize)
let sourceImpl = FFMpegMediaFrameSource(queue: queue, postbox: postbox, userLocation: userLocation, userContentType: userContentType, resourceReference: resourceReference, tempFilePath: nil, streamable: true, video: true, preferSoftwareDecoding: false, fetchAutomatically: true, maximumFetchSize: maximumFetchSize)
let source = QueueLocalObject(queue: queue, generate: {
return sourceImpl
})

View File

@ -27,6 +27,8 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa
let fetchDisposable = MetaDisposable()
let isInitialized = context.videoStream != nil || context.automaticallyFetchHeader
let mediaBox = context.mediaBox
let userLocation = context.userLocation
let userContentType = context.userContentType
let reference = context.fileReference.resourceReference(context.fileReference.media.resource)
let disposable = data.start(next: { result in
let (data, isComplete) = result
@ -35,7 +37,7 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa
semaphore.signal()
} else {
if isInitialized {
fetchDisposable.set(fetchedMediaResource(mediaBox: mediaBox, reference: reference, ranges: [(requestRange, .maximum)]).start())
fetchDisposable.set(fetchedMediaResource(mediaBox: mediaBox, userLocation: userLocation, userContentType: userContentType, reference: reference, ranges: [(requestRange, .maximum)]).start())
}
requiredDataIsNotLocallyAvailable?()
}
@ -98,6 +100,8 @@ private final class SoftwareVideoStream {
private final class UniversalSoftwareVideoSourceImpl {
fileprivate let mediaBox: MediaBox
fileprivate let userLocation: MediaResourceUserLocation
fileprivate let userContentType: MediaResourceUserContentType
fileprivate let fileReference: FileMediaReference
fileprivate let size: Int64
fileprivate let automaticallyFetchHeader: Bool
@ -115,12 +119,14 @@ private final class UniversalSoftwareVideoSourceImpl {
fileprivate var currentNumberOfReads: Int = 0
fileprivate var currentReadBytes: Int64 = 0
init?(mediaBox: MediaBox, fileReference: FileMediaReference, state: ValuePromise<UniversalSoftwareVideoSourceState>, cancelInitialization: Signal<Bool, NoError>, automaticallyFetchHeader: Bool, hintVP9: Bool = false) {
init?(mediaBox: MediaBox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference, state: ValuePromise<UniversalSoftwareVideoSourceState>, cancelInitialization: Signal<Bool, NoError>, automaticallyFetchHeader: Bool, hintVP9: Bool = false) {
guard let size = fileReference.media.size else {
return nil
}
self.mediaBox = mediaBox
self.userLocation = userLocation
self.userContentType = userContentType
self.fileReference = fileReference
self.size = size
self.automaticallyFetchHeader = automaticallyFetchHeader
@ -289,6 +295,8 @@ private enum UniversalSoftwareVideoSourceState {
private final class UniversalSoftwareVideoSourceThreadParams: NSObject {
let mediaBox: MediaBox
let userLocation: MediaResourceUserLocation
let userContentType: MediaResourceUserContentType
let fileReference: FileMediaReference
let state: ValuePromise<UniversalSoftwareVideoSourceState>
let cancelInitialization: Signal<Bool, NoError>
@ -297,6 +305,8 @@ private final class UniversalSoftwareVideoSourceThreadParams: NSObject {
init(
mediaBox: MediaBox,
userLocation: MediaResourceUserLocation,
userContentType: MediaResourceUserContentType,
fileReference: FileMediaReference,
state: ValuePromise<UniversalSoftwareVideoSourceState>,
cancelInitialization: Signal<Bool, NoError>,
@ -304,6 +314,8 @@ private final class UniversalSoftwareVideoSourceThreadParams: NSObject {
hintVP9: Bool
) {
self.mediaBox = mediaBox
self.userLocation = userLocation
self.userContentType = userContentType
self.fileReference = fileReference
self.state = state
self.cancelInitialization = cancelInitialization
@ -333,7 +345,7 @@ private final class UniversalSoftwareVideoSourceThread: NSObject {
let timer = Timer(fireAt: .distantFuture, interval: 0.0, target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.none), userInfo: nil, repeats: false)
runLoop.add(timer, forMode: .common)
let source = UniversalSoftwareVideoSourceImpl(mediaBox: params.mediaBox, fileReference: params.fileReference, state: params.state, cancelInitialization: params.cancelInitialization, automaticallyFetchHeader: params.automaticallyFetchHeader)
let source = UniversalSoftwareVideoSourceImpl(mediaBox: params.mediaBox, userLocation: params.userLocation, userContentType: params.userContentType, fileReference: params.fileReference, state: params.state, cancelInitialization: params.cancelInitialization, automaticallyFetchHeader: params.automaticallyFetchHeader)
Thread.current.threadDictionary["source"] = source
while true {
@ -391,8 +403,8 @@ public final class UniversalSoftwareVideoSource {
}
}
public init(mediaBox: MediaBox, fileReference: FileMediaReference, automaticallyFetchHeader: Bool = false, hintVP9: Bool = false) {
self.thread = Thread(target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.entryPoint(_:)), object: UniversalSoftwareVideoSourceThreadParams(mediaBox: mediaBox, fileReference: fileReference, state: self.stateValue, cancelInitialization: self.cancelInitialization.get(), automaticallyFetchHeader: automaticallyFetchHeader, hintVP9: hintVP9))
public init(mediaBox: MediaBox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference, automaticallyFetchHeader: Bool = false, hintVP9: Bool = false) {
self.thread = Thread(target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.entryPoint(_:)), object: UniversalSoftwareVideoSourceThreadParams(mediaBox: mediaBox, userLocation: userLocation, userContentType: userContentType, fileReference: fileReference, state: self.stateValue, cancelInitialization: self.cancelInitialization.get(), automaticallyFetchHeader: automaticallyFetchHeader, hintVP9: hintVP9))
self.thread.name = "UniversalSoftwareVideoSource"
self.thread.start()
}

View File

@ -263,7 +263,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.zoomableContent = (largestSize.dimensions.cgSize, self.contentNode)
if let largestIndex = representations.firstIndex(where: { $0.representation == largestSize }) {
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: representations[largestIndex].reference).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[largestIndex].reference).start())
}
var id: Int64
@ -281,7 +281,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
if video != previousVideoRepresentations?.last {
let mediaManager = self.context.sharedContext.mediaManager
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: entry.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id, category), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: true, useLargeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoContent = NativeVideoContent(id: .profileVideo(id, category), userLocation: .other, fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: true, useLargeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .overlay)
videoNode.isUserInteractionEnabled = false
videoNode.isHidden = true
@ -613,7 +613,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
}
if let largestIndex = representations.firstIndex(where: { $0.representation == largestSize }) {
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: representations[largestIndex].reference).start())
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[largestIndex].reference).start())
}
default:
break

View File

@ -248,7 +248,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
}
if let videoContent = self.videoContent {
let duration: Double = (self.videoStartTimestamp ?? 0.0) + 4.0
self.preloadDisposable.set(preloadVideoResource(postbox: self.context.account.postbox, resourceReference: videoContent.fileReference.resourceReference(videoContent.fileReference.media.resource), duration: duration).start())
self.preloadDisposable.set(preloadVideoResource(postbox: self.context.account.postbox, userLocation: .other, userContentType: .video, resourceReference: videoContent.fileReference.resourceReference(videoContent.fileReference.media.resource), duration: duration).start())
}
}
}
@ -465,7 +465,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
if let video = videoRepresentations.last, let peerReference = PeerReference(self.peer) {
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: fullSizeOnly, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoContent = NativeVideoContent(id: .profileVideo(id, nil), userLocation: .other, fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: fullSizeOnly, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
if videoContent.id != self.videoContent?.id {
self.videoContent = videoContent

View File

@ -232,8 +232,8 @@ class GroupStickerPackCurrentItemNode: ItemListRevealOptionsItemNode {
var updatedFetchSignal: Signal<FetchResourceSourceType, FetchResourceError>?
if fileUpdated {
if let file = file {
updatedImageSignal = chatMessageSticker(account: item.account, file: file, small: false)
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(file.resource))
updatedImageSignal = chatMessageSticker(account: item.account, userLocation: .other, file: file, small: false)
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(file.resource))
} else {
updatedImageSignal = .single({ _ in return nil })
updatedFetchSignal = .complete()

View File

@ -55,7 +55,7 @@ public func representationFetchRangeForDisplayAtSize(representation: TelegramMed
return nil
}
public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false, synchronousLoad: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<Tuple4<Data?, Data?, ChatMessagePhotoQuality, Bool>, NoError> {
public func chatMessagePhotoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false, synchronousLoad: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<Tuple4<Data?, Data?, ChatMessagePhotoQuality, Bool>, NoError> {
if let progressiveRepresentation = progressiveImageRepresentation(photoReference.media.representations), progressiveRepresentation.progressiveSizes.count > 1 {
enum SizeSource {
case miniThumbnail(data: Data)
@ -130,9 +130,9 @@ public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaRe
})
var fetchDisposable: Disposable?
if autoFetchFullSize {
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(largestByteSize), .default), statsCategory: .image).start()
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(largestByteSize), .default), statsCategory: .image).start()
} else if useMiniThumbnailIfAvailable {
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(thumbnailByteSize), .default), statsCategory: .image).start()
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(thumbnailByteSize), .default), statsCategory: .image).start()
}
return ActionDisposable {
@ -161,9 +161,9 @@ public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaRe
if let _ = decodedThumbnailData {
fetchedThumbnail = .complete()
} else {
fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
}
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image)
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image)
let anyThumbnail: [Signal<(MediaResourceData, ChatMessagePhotoQuality), NoError>]
if tryAdditionalRepresentations {
@ -265,7 +265,7 @@ public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaRe
}
}
private func chatMessageFileDatas(account: Account, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, fetched: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
private func chatMessageFileDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, fetched: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
let thumbnailResource = fetched ? nil : smallestImageRepresentation(fileReference.media.previewRepresentations)?.resource
let fullSizeResource = fileReference.media.resource
@ -282,7 +282,7 @@ private func chatMessageFileDatas(account: Account, fileReference: FileMediaRefe
if !fetched, let _ = decodedThumbnailData {
fetchedThumbnail = .single(.local)
} else if let thumbnailResource = thumbnailResource {
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: statsCategoryForFileWithAttributes(fileReference.media.attributes))
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource), statsCategory: statsCategoryForFileWithAttributes(fileReference.media.attributes))
} else {
fetchedThumbnail = .complete()
}
@ -336,7 +336,7 @@ private let thumbnailGenerationMimeTypes: Set<String> = Set([
"image/heic"
])
private func chatMessageImageFileThumbnailDatas(account: Account, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
private func chatMessageImageFileThumbnailDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
let thumbnailRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations)
let thumbnailResource = thumbnailRepresentation?.resource
let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
@ -345,7 +345,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
if let decodedThumbnailData = decodedThumbnailData {
if autoFetchFullSizeThumbnail, let thumbnailRepresentation = thumbnailRepresentation, (thumbnailRepresentation.dimensions.width > 200 || thumbnailRepresentation.dimensions.height > 200) {
return Signal { subscriber in
let fetchedDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let fetchedDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let thumbnailDisposable = account.postbox.mediaBox.resourceData(thumbnailRepresentation.resource, attemptSynchronously: false).start(next: { next in
let data: Data? = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])
subscriber.putNext(Tuple(data ?? decodedThumbnailData, nil, false))
@ -360,7 +360,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
return .single(Tuple(decodedThumbnailData, nil, false))
}
} else if let thumbnailResource = thumbnailResource {
let fetchedThumbnail: Signal<FetchResourceSourceType, FetchResourceError> = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource))
let fetchedThumbnail: Signal<FetchResourceSourceType, FetchResourceError> = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource))
return Signal { subscriber in
let fetchedDisposable = fetchedThumbnail.start()
let thumbnailDisposable = account.postbox.mediaBox.resourceData(thumbnailResource, pathExtension: pathExtension).start(next: { next in
@ -396,7 +396,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
if let _ = fileReference.media.immediateThumbnailData {
fetchedThumbnail = .complete()
} else if let thumbnailResource = thumbnailResource {
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource))
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource))
} else {
fetchedThumbnail = .complete()
}
@ -442,7 +442,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
return signal
}
private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
let fullSizeResource = fileReference.media.resource
var reducedSizeResource: MediaResource?
if let videoThumbnail = fileReference.media.videoThumbnails.first {
@ -472,7 +472,7 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef
} else if let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) {
if autoFetchFullSizeThumbnail, let thumbnailRepresentation = thumbnailRepresentation, (thumbnailRepresentation.dimensions.width > 200 || thumbnailRepresentation.dimensions.height > 200) {
thumbnail = Signal { subscriber in
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailRepresentation.resource, attemptSynchronously: synchronousLoad).start(next: { next in
let data: Data? = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])
subscriber.putNext(data ?? decodedThumbnailData)
@ -488,7 +488,7 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef
}
} else if let thumbnailResource = thumbnailResource {
thumbnail = Signal { subscriber in
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource, attemptSynchronously: synchronousLoad).start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
}, error: subscriber.putError, completed: subscriber.putCompletion)
@ -569,8 +569,8 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef
return signal
}
public func rawMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> Signal<UIImage?, NoError> {
return chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference, autoFetchFullSize: true)
public func rawMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<UIImage?, NoError> {
return chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: photoReference, autoFetchFullSize: true)
|> map { value -> UIImage? in
let thumbnailData = value._0
let fullSizeData = value._1
@ -587,8 +587,8 @@ public func rawMessagePhoto(postbox: Postbox, photoReference: ImageMediaReferenc
}
}
public func chatMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference, synchronousLoad: Bool = false, highQuality: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad)
public func chatMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, synchronousLoad: Bool = false, highQuality: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: photoReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad)
|> map { _, _, generate in
return generate
}
@ -798,7 +798,7 @@ public func chatMessagePhotoInternal(photoData: Signal<Tuple4<Data?, Data?, Chat
}
}
private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal<Tuple3<Data?, Data?, Bool>, NoError> {
private func chatMessagePhotoThumbnailDatas(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal<Tuple3<Data?, Data?, Bool>, NoError> {
let fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0)
if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(PixelDimensions(width: Int32(fullRepresentationSize.width), height: Int32(fullRepresentationSize.height))) {
@ -812,7 +812,7 @@ private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: Im
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
return .single(Tuple(nil, loadedData, true))
} else {
let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
let thumbnail = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start()
@ -848,8 +848,8 @@ private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: Im
}
}
public func chatMessagePhotoThumbnail(account: Account, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessagePhotoThumbnailDatas(account: account, photoReference: photoReference, onlyFullSize: onlyFullSize)
public func chatMessagePhotoThumbnail(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessagePhotoThumbnailDatas(account: account, userLocation: userLocation, photoReference: photoReference, onlyFullSize: onlyFullSize)
return signal
|> map { value in
let thumbnailData = value._0
@ -941,8 +941,8 @@ public func chatMessagePhotoThumbnail(account: Account, photoReference: ImageMed
}
}
public func chatMessageVideoThumbnail(account: Account, fileReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessageVideoDatas(postbox: account.postbox, fileReference: fileReference, thumbnailSize: true, autoFetchFullSizeThumbnail: true)
public func chatMessageVideoThumbnail(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessageVideoDatas(postbox: account.postbox, userLocation: userLocation, fileReference: fileReference, thumbnailSize: true, autoFetchFullSizeThumbnail: true)
return signal
|> map { value in
@ -1044,8 +1044,8 @@ public func chatMessageVideoThumbnail(account: Account, fileReference: FileMedia
}
}
public func chatSecretPhoto(account: Account, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessagePhotoDatas(postbox: account.postbox, photoReference: photoReference)
public func chatSecretPhoto(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMessagePhotoDatas(postbox: account.postbox, userLocation: userLocation, photoReference: photoReference)
return signal
|> map { value in
let thumbnailData = value._0
@ -1207,8 +1207,8 @@ private func avatarGalleryThumbnailDatas(postbox: Postbox, representations: [Ima
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
return .single(Tuple(nil, loadedData, true))
} else {
let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: representations[smallestIndex].reference, statsCategory: .image)
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: representations[largestIndex].reference, statsCategory: .image)
let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[smallestIndex].reference, statsCategory: .image)
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[largestIndex].reference, statsCategory: .image)
let thumbnail = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start()
@ -1353,7 +1353,7 @@ public func avatarGalleryThumbnailPhoto(account: Account, representations: [Imag
}
}
public func mediaGridMessagePhoto(account: Account, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 127.0, height: 127.0), synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
public func mediaGridMessagePhoto(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 127.0, height: 127.0), synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let useMiniThumbnailIfAvailable: Bool = fullRepresentationSize.width < 40.0
var updatedFullRepresentationSize = fullRepresentationSize
if useMiniThumbnailIfAvailable, let largest = largestImageRepresentation(photoReference.media.representations) {
@ -1361,7 +1361,7 @@ public func mediaGridMessagePhoto(account: Account, photoReference: ImageMediaRe
updatedFullRepresentationSize = largest.dimensions.cgSize
}
}
let signal = chatMessagePhotoDatas(postbox: account.postbox, photoReference: photoReference, fullRepresentationSize: updatedFullRepresentationSize, autoFetchFullSize: true, tryAdditionalRepresentations: useMiniThumbnailIfAvailable, synchronousLoad: synchronousLoad, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
let signal = chatMessagePhotoDatas(postbox: account.postbox, userLocation: userLocation, photoReference: photoReference, fullRepresentationSize: updatedFullRepresentationSize, autoFetchFullSize: true, tryAdditionalRepresentations: useMiniThumbnailIfAvailable, synchronousLoad: synchronousLoad, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
return signal
|> map { value in
@ -1464,7 +1464,7 @@ public func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaRef
}, completed: {
subscriber.putCompletion()
})
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: videoReference.resourceReference(thumbnailResource)).start()
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .gif, reference: videoReference.resourceReference(thumbnailResource)).start()
return ActionDisposable {
data.dispose()
fetched.dispose()
@ -1527,17 +1527,17 @@ public func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaRef
}
}
public func mediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return internalMediaGridMessageVideo(postbox: postbox, videoReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, overlayColor: overlayColor, nilForEmptyResult: nilForEmptyResult, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, overlayColor: overlayColor, nilForEmptyResult: nilForEmptyResult, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
|> map {
return $0.1
}
}
public func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
let signal: Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError>
if let imageReference = imageReference {
signal = chatMessagePhotoDatas(postbox: postbox, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad)
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad)
|> map { value -> Tuple3<Data?, Tuple2<Data, String>?, Bool> in
let thumbnailData = value._0
let fullSizeData = value._1
@ -1545,7 +1545,7 @@ public func internalMediaGridMessageVideo(postbox: Postbox, videoReference: File
return Tuple(thumbnailData, fullSizeData.flatMap({ Tuple($0, "") }), fullSizeComplete)
}
} else {
signal = chatMessageVideoDatas(postbox: postbox, fileReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail)
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, fileReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail)
}
return signal
@ -1787,9 +1787,9 @@ public func chatMessagePhotoStatus(context: AccountContext, messageId: MessageId
}
}
public func standaloneChatMessagePhotoInteractiveFetched(account: Account, photoReference: ImageMediaReference) -> Signal<FetchResourceSourceType, FetchResourceError> {
public func standaloneChatMessagePhotoInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<FetchResourceSourceType, FetchResourceError> {
if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true)
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
return .single(type)
}
@ -1798,14 +1798,14 @@ public func standaloneChatMessagePhotoInteractiveFetched(account: Account, photo
}
}
public func chatMessagePhotoInteractiveFetched(context: AccountContext, photoReference: ImageMediaReference, displayAtSize: Int?, storeToDownloadsPeerType: MediaAutoDownloadPeerType?) -> Signal<Never, NoError> {
public func chatMessagePhotoInteractiveFetched(context: AccountContext, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, displayAtSize: Int?, storeToDownloadsPeerType: MediaAutoDownloadPeerType?) -> Signal<Never, NoError> {
if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) {
var fetchRange: (Range<Int64>, MediaBoxFetchPriority)?
if let displayAtSize = displayAtSize, let range = representationFetchRangeForDisplayAtSize(representation: largestRepresentation, dimension: displayAtSize) {
fetchRange = (range, .default)
}
return fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), range: fetchRange, statsCategory: .image, reportResultStatus: true)
return fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(largestRepresentation.resource), range: fetchRange, statsCategory: .image, reportResultStatus: true)
|> mapToSignal { type -> Signal<FetchResourceSourceType, FetchResourceError> in
if case .remote = type, let peerType = storeToDownloadsPeerType {
return storeDownloadedMedia(storeManager: context.downloadedMediaStoreManager, media: photoReference.abstract, peerType: peerType)
@ -1831,15 +1831,15 @@ public func chatMessagePhotoCancelInteractiveFetch(account: Account, photoRefere
}
}
public func chatMessageWebFileInteractiveFetched(account: Account, image: TelegramMediaWebFile) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: image.resource), statsCategory: .image)
public func chatMessageWebFileInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, image: TelegramMediaWebFile) -> Signal<FetchResourceSourceType, FetchResourceError> {
return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: .standalone(resource: image.resource), statsCategory: .image)
}
public func chatMessageWebFileCancelInteractiveFetch(account: Account, image: TelegramMediaWebFile) {
return account.postbox.mediaBox.cancelInteractiveResourceFetch(image.resource)
}
public func chatWebpageSnippetFileData(account: Account, mediaReference: AnyMediaReference, resource: MediaResource) -> Signal<Data?, NoError> {
public func chatWebpageSnippetFileData(account: Account, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference, resource: MediaResource) -> Signal<Data?, NoError> {
let resourceData = account.postbox.mediaBox.resourceData(resource)
|> map { next in
return next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedIfSafe)
@ -1853,12 +1853,12 @@ public func chatWebpageSnippetFileData(account: Account, mediaReference: AnyMedi
}, completed: {
subscriber.putCompletion()
}))
disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: mediaReference.resourceReference(resource)).start())
disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: mediaReference.resourceReference(resource)).start())
return disposable
}
}
public func chatWebpageSnippetPhotoData(account: Account, photoReference: ImageMediaReference) -> Signal<Data?, NoError> {
public func chatWebpageSnippetPhotoData(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<Data?, NoError> {
if let closestRepresentation = photoReference.media.representationForDisplayAtSize(PixelDimensions(width: 120, height: 120)) {
let resourceData = account.postbox.mediaBox.resourceData(closestRepresentation.resource)
|> map { next in
@ -1873,7 +1873,7 @@ public func chatWebpageSnippetPhotoData(account: Account, photoReference: ImageM
}, completed: {
subscriber.putCompletion()
}))
disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(closestRepresentation.resource)).start())
disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(closestRepresentation.resource)).start())
return disposable
}
} else {
@ -1881,8 +1881,8 @@ public func chatWebpageSnippetPhotoData(account: Account, photoReference: ImageM
}
}
public func chatWebpageSnippetFile(account: Account, mediaReference: AnyMediaReference, representation: TelegramMediaImageRepresentation) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatWebpageSnippetFileData(account: account, mediaReference: mediaReference, resource: representation.resource)
public func chatWebpageSnippetFile(account: Account, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference, representation: TelegramMediaImageRepresentation) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatWebpageSnippetFileData(account: account, userLocation: userLocation, mediaReference: mediaReference, resource: representation.resource)
return signal |> map { fullSizeData in
return { arguments in
@ -1947,8 +1947,8 @@ public func chatWebpageSnippetFile(account: Account, mediaReference: AnyMediaRef
}
}
public func chatWebpageSnippetPhoto(account: Account, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatWebpageSnippetPhotoData(account: account, photoReference: photoReference)
public func chatWebpageSnippetPhoto(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatWebpageSnippetPhotoData(account: account, userLocation: userLocation, photoReference: photoReference)
return signal |> map { fullSizeData in
return { arguments in
@ -1992,15 +1992,15 @@ public func chatWebpageSnippetPhoto(account: Account, photoReference: ImageMedia
}
}
public func chatMessageVideo(postbox: Postbox, videoReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return mediaGridMessageVideo(postbox: postbox, videoReference: videoReference)
public func chatMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return mediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: videoReference)
}
private func chatSecretMessageVideoData(account: Account, fileReference: FileMediaReference) -> Signal<Data?, NoError> {
private func chatSecretMessageVideoData(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) -> Signal<Data?, NoError> {
if let smallestRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
let thumbnailResource = smallestRepresentation.resource
let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource))
let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource))
let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
@ -2022,8 +2022,8 @@ private func chatSecretMessageVideoData(account: Account, fileReference: FileMed
}
}
public func chatSecretMessageVideo(account: Account, videoReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatSecretMessageVideoData(account: account, fileReference: videoReference)
public func chatSecretMessageVideo(account: Account, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatSecretMessageVideoData(account: account, userLocation: userLocation, fileReference: videoReference)
return signal
|> map { thumbnailData in
@ -2181,12 +2181,12 @@ public func drawImage(context: CGContext, image: CGImage, orientation: UIImage.O
}
}
public func chatMessageImageFile(account: Account, fileReference: FileMediaReference, thumbnail: Bool, fetched: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
public func chatMessageImageFile(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, thumbnail: Bool, fetched: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal: Signal<Tuple3<Data?, String?, Bool>, NoError>
if thumbnail {
signal = chatMessageImageFileThumbnailDatas(account: account, fileReference: fileReference, autoFetchFullSizeThumbnail: true)
signal = chatMessageImageFileThumbnailDatas(account: account, userLocation: userLocation, fileReference: fileReference, autoFetchFullSizeThumbnail: true)
} else {
signal = chatMessageFileDatas(account: account, fileReference: fileReference, progressive: false, fetched: fetched)
signal = chatMessageFileDatas(account: account, userLocation: userLocation, fileReference: fileReference, progressive: false, fetched: fetched)
}
return signal
@ -2319,8 +2319,8 @@ public func chatMessageImageFile(account: Account, fileReference: FileMediaRefer
}
}
public func instantPageImageFile(account: Account, fileReference: FileMediaReference, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessageFileDatas(account: account, fileReference: fileReference, progressive: false, fetched: fetched)
public func instantPageImageFile(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessageFileDatas(account: account, userLocation: userLocation, fileReference: fileReference, progressive: false, fetched: fetched)
|> map { value in
let fullSizePath = value._1
let fullSizeComplete = value._2
@ -2447,9 +2447,9 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR
if let _ = decodedThumbnailData {
fetchedThumbnail = .complete()
} else {
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference)
fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[smallestIndex].reference)
}
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[largestIndex].reference)
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .image, reference: representations[largestIndex].reference)
let thumbnail = Signal<Data?, NoError> { subscriber in
if let decodedThumbnailData = decodedThumbnailData {
@ -2832,7 +2832,7 @@ public func playerAlbumArt(postbox: Postbox, engine: TelegramEngine, fileReferen
if let fileReference = fileReference, let smallestRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
let thumbnailResource = smallestRepresentation.resource
let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource))
let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .image, reference: fileReference.resourceReference(thumbnailResource))
let thumbnail = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start()

View File

@ -42,9 +42,9 @@ public enum FetchResourceError {
case generic
}
private struct ResourceStorePaths {
let partial: String
let complete: String
public struct ResourceStorePaths {
public let partial: String
public let complete: String
}
public struct MediaResourceData {
@ -204,14 +204,18 @@ public final class MediaBox {
self.dataFileManager = MediaBoxFileManager(queue: self.dataQueue)
let _ = self.ensureDirectoryCreated
//self.updateResourceIndex()
}
public func setMaxStoreTimes(general: Int32, shortLived: Int32, gigabytesLimit: Int32) {
self.timeBasedCleanup.setMaxStoreTimes(general: general, shortLived: shortLived, gigabytesLimit: gigabytesLimit)
}
private func idForFileName(name: String) -> String {
if name.hasSuffix("_partial") {
private static func idForFileName(name: String) -> String {
if name.hasSuffix("_partial.meta") {
return String(name[name.startIndex ..< name.index(name.endIndex, offsetBy: -13)])
} else if name.hasSuffix("_partial") {
return String(name[name.startIndex ..< name.index(name.endIndex, offsetBy: -8)])
} else {
return name
@ -230,7 +234,7 @@ public final class MediaBox {
return "\(self.basePath)/\(fileNameForId(id))"
}
private func storePathsForId(_ id: MediaResourceId) -> ResourceStorePaths {
public func storePathsForId(_ id: MediaResourceId) -> ResourceStorePaths {
return ResourceStorePaths(partial: "\(self.basePath)/\(fileNameForId(id))_partial", complete: "\(self.basePath)/\(fileNameForId(id))")
}
@ -595,7 +599,14 @@ public final class MediaBox {
}
if let location = parameters?.location {
self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId.toInt64(), messageNamespace: UInt8(clamping: location.messageId.namespace), messageId: location.messageId.id), to: resource.id.stringRepresentation.data(using: .utf8)!)
var messageNamespace: Int32 = 0
var messageIdValue: Int32 = 0
if let messageId = location.messageId {
messageNamespace = messageId.namespace
messageIdValue = messageId.id
}
self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId.toInt64(), messageNamespace: UInt8(clamping: messageNamespace), messageId: messageIdValue), to: resource.id.stringRepresentation.data(using: .utf8)!)
}
guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
@ -761,7 +772,14 @@ public final class MediaBox {
let paths = self.storePathsForId(resource.id)
if let location = parameters?.location {
self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId.toInt64(), messageNamespace: UInt8(clamping: location.messageId.namespace), messageId: location.messageId.id), to: resource.id.stringRepresentation.data(using: .utf8)!)
var messageNamespace: Int32 = 0
var messageIdValue: Int32 = 0
if let messageId = location.messageId {
messageNamespace = messageId.namespace
messageIdValue = messageId.id
}
self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId.toInt64(), messageNamespace: UInt8(clamping: messageNamespace), messageId: messageIdValue), to: resource.id.stringRepresentation.data(using: .utf8)!)
}
if let _ = fileSize(paths.complete) {
@ -1245,6 +1263,51 @@ public final class MediaBox {
}
}
public func updateResourceIndex(completion: @escaping () -> Void) -> Disposable {
let basePath = self.basePath
let storageBox = self.storageBox
var isCancelled: Bool = false
let processQueue = Queue(name: "UpdateResourceIndex", qos: .background)
processQueue.async {
if isCancelled {
return
}
let scanContext = ScanFilesContext(path: basePath)
func processNext() {
processQueue.async {
if isCancelled {
return
}
let results = scanContext.nextBatch(count: 32000)
if results.isEmpty {
completion()
return
}
storageBox.addEmptyReferencesIfNotReferenced(ids: results.map { name -> Data in
return MediaBox.idForFileName(name: name).data(using: .utf8)!
}, completion: { addedCount in
if addedCount != 0 {
postboxLog("UpdateResourceIndex: added \(addedCount) unreferenced ids")
}
processNext()
})
}
}
processNext()
}
return ActionDisposable {
isCancelled = true
}
}
public func collectAllResourceUsage() -> Signal<[(id: String?, path: String, size: Int64)], NoError> {
return Signal { subscriber in
self.dataQueue.async {
@ -1263,7 +1326,7 @@ public final class MediaBox {
if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
fileIds.insert(fileId)
result.append((id: self.idForFileName(name: url.lastPathComponent), path: url.lastPathComponent, size: Int64(value)))
result.append((id: MediaBox.idForFileName(name: url.lastPathComponent), path: url.lastPathComponent, size: Int64(value)))
//paths.append(url.lastPathComponent)
}
}
@ -1602,3 +1665,120 @@ public final class MediaBox {
}
}
private final class ScanFilesContext {
private let path: String
private var dirHandle: UnsafeMutablePointer<DIR>?
private let pathBuffer: UnsafeMutablePointer<Int8>
init(path: String) {
self.path = path
self.dirHandle = opendir(path)
self.pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
}
deinit {
if let dirHandle = self.dirHandle {
closedir(dirHandle)
}
free(self.pathBuffer)
}
func nextBatch(count: Int) -> [String] {
guard let dirHandle = self.dirHandle else {
return []
}
var result: [String] = []
while true {
guard let dirp = readdir(dirHandle) else {
closedir(dirHandle)
self.dirHandle = nil
break
}
if dirp.pointee.d_type != DT_REG {
continue
}
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
continue
}
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
continue
}
strncpy(self.pathBuffer, self.path, 1024)
strncat(self.pathBuffer, "/", 1024)
strncat(self.pathBuffer, &dirp.pointee.d_name.0, 1024)
//puts(pathBuffer)
//puts("\n")
var value = stat()
if stat(self.pathBuffer, &value) == 0 {
if let itemPath = String(data: Data(bytes: &dirp.pointee.d_name.0, count: Int(dirp.pointee.d_namlen)), encoding: .utf8) {
result.append(itemPath)
}
/*result.totalSize += UInt64(value.st_size)
inodes.append(InodeInfo(
inode: value.st_ino,
timestamp: Int32(clamping: value.st_mtimespec.tv_sec),
size: UInt32(clamping: value.st_size)
))*/
}
}
return result
}
}
/*private func scanFiles(at path: String, inodes: inout [InodeInfo]) -> ScanFilesResult {
var result = ScanFilesResult()
if let dp = opendir(path) {
let pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
defer {
free(pathBuffer)
}
while true {
guard let dirp = readdir(dp) else {
break
}
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
continue
}
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
continue
}
strncpy(pathBuffer, path, 1024)
strncat(pathBuffer, "/", 1024)
strncat(pathBuffer, &dirp.pointee.d_name.0, 1024)
//puts(pathBuffer)
//puts("\n")
var value = stat()
if stat(pathBuffer, &value) == 0 {
if value.st_mtimespec.tv_sec < minTimestamp {
unlink(pathBuffer)
result.unlinkedCount += 1
} else {
result.totalSize += UInt64(value.st_size)
inodes.append(InodeInfo(
inode: value.st_ino,
timestamp: Int32(clamping: value.st_mtimespec.tv_sec),
size: UInt32(clamping: value.st_size)
))
}
}
}
closedir(dp)
}
return result
}*/

View File

@ -41,24 +41,37 @@ public protocol MediaResourceFetchInfo {
public final class MediaResourceStorageLocation {
public let peerId: PeerId
public let messageId: MessageId
public let messageId: MessageId?
public init(peerId: PeerId, messageId: MessageId) {
public init(peerId: PeerId, messageId: MessageId?) {
self.peerId = peerId
self.messageId = messageId
}
}
public enum MediaResourceUserContentType: UInt8, Equatable {
case image = 0
case video = 1
case audio = 2
case file = 3
case gif = 4
case emoji = 5
case sticker = 6
case other = 7
}
public struct MediaResourceFetchParameters {
public let tag: MediaResourceFetchTag?
public let info: MediaResourceFetchInfo?
public let location: MediaResourceStorageLocation?
public let contentType: MediaResourceUserContentType
public let isRandomAccessAllowed: Bool
public init(tag: MediaResourceFetchTag?, info: MediaResourceFetchInfo?, location: MediaResourceStorageLocation?, isRandomAccessAllowed: Bool) {
public init(tag: MediaResourceFetchTag?, info: MediaResourceFetchInfo?, location: MediaResourceStorageLocation?, contentType: MediaResourceUserContentType, isRandomAccessAllowed: Bool) {
self.tag = tag
self.info = info
self.location = location
self.contentType = contentType
self.isRandomAccessAllowed = isRandomAccessAllowed
}
}

View File

@ -145,6 +145,79 @@ public final class StorageBox {
self.valueBox.commit()
}
func addEmptyReferencesIfNotReferenced(ids: [Data]) -> Int {
self.valueBox.begin()
var addedCount = 0
for id in ids {
let reference = Reference(peerId: 0, messageNamespace: 0, messageId: 0)
let hashId = md5Hash(id)
let mainKey = ValueBoxKey(length: 16)
mainKey.setData(0, value: hashId.data)
if self.valueBox.exists(self.hashIdToIdTable, key: mainKey) {
continue
}
addedCount += 1
self.valueBox.setOrIgnore(self.hashIdToIdTable, key: mainKey, value: MemoryBuffer(data: id))
let idKey = ValueBoxKey(length: hashId.data.count + 8 + 1 + 4)
idKey.setData(0, value: hashId.data)
idKey.setInt64(hashId.data.count, value: reference.peerId)
idKey.setUInt8(hashId.data.count + 8, value: reference.messageNamespace)
idKey.setInt32(hashId.data.count + 8 + 1, value: reference.messageId)
var alreadyStored = false
if !self.valueBox.exists(self.idToReferenceTable, key: idKey) {
self.valueBox.setOrIgnore(self.idToReferenceTable, key: idKey, value: MemoryBuffer())
} else {
alreadyStored = true
}
if !alreadyStored {
var idInPeerIdStored = false
let peerIdIdKey = ValueBoxKey(length: 8 + 16)
peerIdIdKey.setInt64(0, value: reference.peerId)
peerIdIdKey.setData(8, value: hashId.data)
var peerIdIdCount: Int32 = 0
if let value = self.valueBox.get(self.peerIdToIdTable, key: peerIdIdKey) {
idInPeerIdStored = true
if value.length == 4 {
memcpy(&peerIdIdCount, value.memory, 4)
} else {
assertionFailure()
}
}
peerIdIdCount += 1
self.valueBox.set(self.peerIdToIdTable, key: peerIdIdKey, value: MemoryBuffer(memory: &peerIdIdCount, capacity: 4, length: 4, freeWhenDone: false))
if !idInPeerIdStored {
let peerIdKey = ValueBoxKey(length: 8)
peerIdKey.setInt64(0, value: reference.peerId)
var peerIdCount: Int32 = 0
if let value = self.valueBox.get(self.peerIdTable, key: peerIdKey) {
if value.length == 4 {
memcpy(&peerIdCount, value.memory, 4)
} else {
assertionFailure()
}
}
peerIdCount += 1
self.valueBox.set(self.peerIdTable, key: peerIdKey, value: MemoryBuffer(memory: &peerIdCount, capacity: 4, length: 4, freeWhenDone: false))
}
}
}
self.valueBox.commit()
return addedCount
}
func remove(ids: [Data]) {
self.valueBox.begin()
@ -247,6 +320,8 @@ public final class StorageBox {
var currentId: Data?
var currentReferences: [Reference] = []
let mainKey = ValueBoxKey(length: 16)
self.valueBox.scan(self.idToReferenceTable, keys: { key in
let id = key.getData(0, length: 16)
@ -260,7 +335,10 @@ public final class StorageBox {
currentReferences.append(reference)
} else {
if let currentId = currentId, !currentReferences.isEmpty {
result.append(StorageBox.Entry(id: currentId, references: currentReferences))
mainKey.setData(0, value: currentId)
if let value = self.valueBox.get(self.hashIdToIdTable, key: mainKey) {
result.append(StorageBox.Entry(id: value.makeData(), references: currentReferences))
}
currentReferences.removeAll(keepingCapacity: true)
}
currentId = id
@ -324,6 +402,14 @@ public final class StorageBox {
}
}
public func addEmptyReferencesIfNotReferenced(ids: [Data], completion: @escaping (Int) -> Void) {
self.impl.with { impl in
let addedCount = impl.addEmptyReferencesIfNotReferenced(ids: ids)
completion(addedCount)
}
}
public func remove(ids: [Data]) {
self.impl.with { impl in
impl.remove(ids: ids)

View File

@ -165,6 +165,7 @@ private final class PhoneView: UIView {
let videoContent = NativeVideoContent(
id: .message(1, MediaId(namespace: 0, id: Int64.random(in: 0..<Int64.max))),
userLocation: .other,
fileReference: .standalone(media: file),
streamVideo: .conservative,
loopVideo: true,

View File

@ -106,7 +106,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
// }
for (_, video) in promoConfiguration.videos {
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, userLocation: .other, userContentType: .video, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
}
}
})
@ -123,9 +123,9 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
for item in view.items {
if let mediaItem = item.contents.get(RecentMediaItem.self) {
let file = mediaItem.media
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .standalone(media: file), resource: file.resource).start())
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start())
if let effect = file.videoThumbnails.first {
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .standalone(media: file), resource: effect.resource).start())
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file), resource: effect.resource).start())
}
}
}

View File

@ -1277,9 +1277,9 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
for item in view.items {
if let mediaItem = item.contents.get(RecentMediaItem.self) {
let file = mediaItem.media
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .standalone(media: file), resource: file.resource).start())
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start())
if let effect = file.videoThumbnails.first {
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .standalone(media: file), resource: effect.resource).start())
strongSelf.preloadDisposableSet.add(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file), resource: effect.resource).start())
}
}
}
@ -2015,7 +2015,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
strongSelf.selectedProductId = strongSelf.products?.last?.id
for (_, video) in promoConfiguration.videos {
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, userLocation: .other, userContentType: .video, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
}
}

View File

@ -115,12 +115,12 @@ private class StickerNode: ASDisplayNode {
let pathPrefix = context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
animationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker), width: Int(fittedDimensions.width * 1.6), height: Int(fittedDimensions.height * 1.6), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, file: file, small: false, size: fittedDimensions))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: file, small: false, size: fittedDimensions))
self.disposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: .standalone(media: file), resource: file.resource).start())
self.disposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start())
if let effect = file.videoThumbnails.first {
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: .standalone(media: file), resource: effect.resource).start())
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: effect.resource).start())
let source = AnimatedStickerResourceSource(account: self.context.account, resource: effect.resource, fitzModifier: nil)

View File

@ -277,7 +277,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
return .single(nil)
}
return Signal { subscriber in
let fetchDisposable = freeMediaFileInteractiveFetched(account: context.account, fileReference: .standalone(media: file)).start()
let fetchDisposable = freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file)).start()
let dataDisposable = (context.account.postbox.mediaBox.resourceData(file.resource)
|> filter(\.complete)
|> take(1)).start(next: { data in
@ -1807,6 +1807,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
for animationLayer in allLayers {
let baseItemLayer = InlineStickerItemLayer(
context: itemNode.context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: itemNode.item.listAnimation.fileId.id, file: itemNode.item.listAnimation),
file: itemNode.item.listAnimation,
@ -2418,6 +2419,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
for animationLayer in allLayers {
let baseItemLayer = InlineStickerItemLayer(
context: itemNode.context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: itemNode.item.listAnimation.fileId.id, file: itemNode.item.listAnimation),
file: itemNode.item.listAnimation,

View File

@ -135,11 +135,11 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
strongSelf.animateInAnimationNode = nil
}
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.appearAnimation.resource)).start()
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.stillAnimation.resource)).start()
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.listAnimation.resource)).start()
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .standalone(resource: item.appearAnimation.resource)).start()
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .standalone(resource: item.stillAnimation.resource)).start()
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .standalone(resource: item.listAnimation.resource)).start()
if let applicationAnimation = item.applicationAnimation {
self.fetchFullAnimationDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: applicationAnimation.resource)).start()
self.fetchFullAnimationDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .standalone(resource: applicationAnimation.resource)).start()
}
}

View File

@ -15,15 +15,18 @@ public enum FetchMediaDataState {
case data(MediaResourceData)
}
public func fetchMediaData(context: AccountContext, postbox: Postbox, mediaReference: AnyMediaReference) -> Signal<(FetchMediaDataState, Bool), NoError> {
public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal<(FetchMediaDataState, Bool), NoError> {
var resource: MediaResource?
var isImage = true
var fileExtension: String?
var userContentType: MediaResourceUserContentType = .other
if let image = mediaReference.media as? TelegramMediaImage {
userContentType = .image
if let representation = largestImageRepresentation(image.representations) {
resource = representation.resource
}
} else if let file = mediaReference.media as? TelegramMediaFile {
userContentType = MediaResourceUserContentType(file: file)
resource = file.resource
if file.isVideo || file.mimeType.hasPrefix("video/") {
isImage = false
@ -47,7 +50,7 @@ public func fetchMediaData(context: AccountContext, postbox: Postbox, mediaRefer
if let resource = resource {
let fetchedData: Signal<FetchMediaDataState, NoError> = Signal { subscriber in
let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: mediaReference.resourceReference(resource)).start()
let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: mediaReference.resourceReference(resource)).start()
let status = postbox.mediaBox.resourceStatus(resource).start(next: { status in
switch status {
case .Local:
@ -80,8 +83,8 @@ public func fetchMediaData(context: AccountContext, postbox: Postbox, mediaRefer
}
}
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, mediaReference: AnyMediaReference) -> Signal<Float, NoError> {
return fetchMediaData(context: context, postbox: postbox, mediaReference: mediaReference)
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal<Float, NoError> {
return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, mediaReference: mediaReference)
|> mapToSignal { state, isImage -> Signal<Float, NoError> in
switch state {
case let .progress(value):
@ -134,8 +137,8 @@ public func saveToCameraRoll(context: AccountContext, postbox: Postbox, mediaRef
}
}
public func copyToPasteboard(context: AccountContext, postbox: Postbox, mediaReference: AnyMediaReference) -> Signal<Void, NoError> {
return fetchMediaData(context: context, postbox: postbox, mediaReference: mediaReference)
public func copyToPasteboard(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal<Void, NoError> {
return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, mediaReference: mediaReference)
|> mapToSignal { state, isImage -> Signal<Void, NoError> in
if case let .data(data) = state, data.complete {
return Signal<Void, NoError> { subscriber in

View File

@ -47,7 +47,7 @@ func faqSearchableItems(context: AccountContext, resolvedUrl: Signal<ResolvedUrl
nextIndex += 1
}
let item = SettingsSearchableItem(id: .faq(index), title: text.plainText, alternate: [], icon: .faq, breadcrumbs: [strings.SettingsSearch_FAQ, currentSection], present: { context, _, present in
present(.push, InstantPageController(context: context, webPage: webPage, sourcePeerType: .channel, anchor: anchor))
present(.push, InstantPageController(context: context, webPage: webPage, sourceLocation: InstantPageSourceLocation(userLocation: .other, peerType: .channel), anchor: anchor))
})
if index == 1 {
results.insert(item, at: 0)

View File

@ -1109,7 +1109,10 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
return context.account.postbox.transaction { transaction -> [(peer: FoundPeer, value: Int32)] in
var result: [(peer: FoundPeer, value: Int32)] = []
for (peerId, value) in accountSpecificSettings.peerStorageTimeoutExceptions {
for item in accountSpecificSettings.peerStorageTimeoutExceptions {
let peerId = item.key
let value = item.value
guard let peer = transaction.getPeer(peerId) else {
continue
}

View File

@ -242,7 +242,10 @@ public func storageUsageExceptionsScreen(
return context.account.postbox.transaction { transaction -> [(peer: FoundPeer, value: Int32)] in
var result: [(peer: FoundPeer, value: Int32)] = []
for (peerId, value) in accountSpecificSettings.peerStorageTimeoutExceptions {
for item in accountSpecificSettings.peerStorageTimeoutExceptions {
let peerId = item.key
let value = item.value
guard let peer = transaction.getPeer(peerId) else {
continue
}
@ -324,7 +327,13 @@ public func storageUsageExceptionsScreen(
let _ = updateAccountSpecificCacheStorageSettingsInteractively(postbox: context.account.postbox, { settings in
var settings = settings
settings.peerStorageTimeoutExceptions[peerId] = Int32.max
for i in 0 ..< settings.peerStorageTimeoutExceptions.count {
if settings.peerStorageTimeoutExceptions[i].key == peerId {
settings.peerStorageTimeoutExceptions.remove(at: i)
break
}
}
settings.peerStorageTimeoutExceptions.append(AccountSpecificCacheStorageSettings.Value(key: peerId, value: Int32.max))
return settings
}).start()
@ -339,9 +348,24 @@ public func storageUsageExceptionsScreen(
var settings = settings
if let value = value {
settings.peerStorageTimeoutExceptions[peerId] = value
var found = false
for i in 0 ..< settings.peerStorageTimeoutExceptions.count {
if settings.peerStorageTimeoutExceptions[i].key == peerId {
found = true
settings.peerStorageTimeoutExceptions[i] = AccountSpecificCacheStorageSettings.Value(key: peerId, value: value)
break
}
}
if !found {
settings.peerStorageTimeoutExceptions.append(AccountSpecificCacheStorageSettings.Value(key: peerId, value: value))
}
} else {
settings.peerStorageTimeoutExceptions.removeValue(forKey: peerId)
for i in 0 ..< settings.peerStorageTimeoutExceptions.count {
if settings.peerStorageTimeoutExceptions[i].key == peerId {
settings.peerStorageTimeoutExceptions.remove(at: i)
break
}
}
}
return settings

View File

@ -431,7 +431,7 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
animatedStickerNode.autoplay = true
animatedStickerNode.visibility = strongSelf.visibilityStatus
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)

View File

@ -1230,7 +1230,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
wallpaperSignal = cachedWallpaper(account: context.account, slug: file.slug, settings: colorWallpaper.settings)
|> mapToSignal { cachedWallpaper in
if let wallpaper = cachedWallpaper?.wallpaper, case let .file(file) = wallpaper {
let _ = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start()
let _ = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start()
return .single(wallpaper)

View File

@ -272,7 +272,7 @@ private final class ThemeGridThemeItemIconNode : ASDisplayNode {
animatedStickerNode.autoplay = true
animatedStickerNode.visibility = true
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)

View File

@ -115,7 +115,7 @@ final class ThemeGridSearchItemNode: GridItemNode {
}
if !representations.isEmpty {
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage), fullRepresentationSize: CGSize(width: 512, height: 512))
updateImageSignal = mediaGridMessagePhoto(account: item.account, userLocation: .other, photoReference: .standalone(media: tmpImage), fullRepresentationSize: CGSize(width: 512, height: 512))
} else {
updateImageSignal = .complete()
}

View File

@ -262,7 +262,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
strongSelf.remoteChatBackgroundNode.setSignal(signal)
strongSelf.fetchDisposable.set(fetchedMediaResource(mediaBox: context.sharedContext.accountManager.mediaBox, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start())
strongSelf.fetchDisposable.set(fetchedMediaResource(mediaBox: context.sharedContext.accountManager.mediaBox, userLocation: .other, userContentType: .other, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start())
let account = strongSelf.context.account
let statusSignal = strongSelf.context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource)

View File

@ -1187,7 +1187,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
wallpaperSignal = cachedWallpaper(account: context.account, slug: file.slug, settings: colorWallpaper.settings)
|> mapToSignal { cachedWallpaper in
if let wallpaper = cachedWallpaper?.wallpaper, case let .file(file) = wallpaper {
let _ = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start()
let _ = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start()
return .single(wallpaper)

View File

@ -422,7 +422,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false)
}
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference)
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: convertedRepresentations[convertedRepresentations.count - 1].reference)
let account = self.context.account
statusSignal = self.context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource)
|> take(1)
@ -452,7 +452,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false)
if let largestIndex = convertedRepresentations.firstIndex(where: { $0.representation == largestSize }) {
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: convertedRepresentations[largestIndex].reference)
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: convertedRepresentations[largestIndex].reference)
} else {
fetchSignal = .complete()
}
@ -546,8 +546,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
signal = chatMessagePhoto(postbox: context.account.postbox, photoReference: .standalone(media: tmpImage))
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .media(media: .standalone(media: tmpImage), resource: imageResource))
signal = chatMessagePhoto(postbox: context.account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage))
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .media(media: .standalone(media: tmpImage), resource: imageResource))
statusSignal = context.account.postbox.mediaBox.resourceStatus(imageResource)
} else {
displaySize = CGSize(width: 1.0, height: 1.0)

View File

@ -87,7 +87,7 @@ private enum ExternalShareResourceStatus {
private func collectExternalShareResource(postbox: Postbox, resourceReference: MediaResourceReference, statsCategory: MediaResourceStatsCategory) -> Signal<ExternalShareResourceStatus, NoError> {
return Signal { subscriber in
let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: statsCategory).start()
let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .other, reference: resourceReference, statsCategory: statsCategory).start()
let data = postbox.mediaBox.resourceData(resourceReference.resource, option: .complete(waitUntilFetchStatus: false)).start(next: { value in
if value.complete {
subscriber.putNext(.done(value))
@ -140,7 +140,7 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor
return .single(.progress)
case let .done(data):
if file.isSticker, !file.isAnimatedSticker, let dimensions = file.dimensions {
return chatMessageSticker(postbox: postbox, file: file, small: false, fetched: true, onlyFullSize: true)
return chatMessageSticker(postbox: postbox, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: true)
|> map { f -> ExternalShareItemStatus in
let context = f(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.cgSize, boundingSize: dimensions.cgSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil, scale: 1.0))
if let image = context?.generateImage() {
@ -973,7 +973,7 @@ public final class ShareController: ViewController {
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
}
return SaveToCameraRoll.saveToCameraRoll(context: context, postbox: postbox, mediaReference: .message(message: MessageReference(message), media: media))
return SaveToCameraRoll.saveToCameraRoll(context: context, postbox: postbox, userLocation: .peer(message.id.peerId), mediaReference: .message(message: MessageReference(message), media: media))
} else {
return nil
}
@ -1000,7 +1000,7 @@ public final class ShareController: ViewController {
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
}
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, mediaReference: .standalone(media: media)) |> map(Optional.init), dismissImmediately: true, completion: {})
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: .standalone(media: media)) |> map(Optional.init), dismissImmediately: true, completion: {})
}
private func saveToCameraRoll(mediaReference: AnyMediaReference) {
@ -1010,7 +1010,7 @@ public final class ShareController: ViewController {
} else {
context = self.sharedContext.makeTempAccountContext(account: self.currentAccount)
}
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, mediaReference: mediaReference) |> map(Optional.init), dismissImmediately: true, completion: {})
self.controllerNode.transitionToProgressWithValue(signal: SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: mediaReference) |> map(Optional.init), dismissImmediately: true, completion: {})
}
private func switchToAccount(account: Account, animateIn: Bool) {

View File

@ -254,7 +254,7 @@ public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareConte
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: 12345), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: size, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
let videoContent = NativeVideoContent(id: .message(1, MediaId(namespace: 0, id: 1)), fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
let videoContent = NativeVideoContent(id: .message(1, MediaId(namespace: 0, id: 1)), userLocation: .other, fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
let videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: sharedContext.mediaManager.audioSession, manager: sharedContext.mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded)
videoNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: 2.0))

View File

@ -37,7 +37,7 @@ public final class SoftwareVideoLayerFrameManager {
private var didStart = false
public var started: () -> Void = { }
public init(account: Account, fileReference: FileMediaReference, layerHolder: SampleBufferLayer?, layer: AVSampleBufferDisplayLayer? = nil, hintVP9: Bool = false) {
public init(account: Account, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference, layerHolder: SampleBufferLayer?, layer: AVSampleBufferDisplayLayer? = nil, hintVP9: Bool = false) {
var resource = fileReference.media.resource
var secondaryResource: MediaResource?
for attribute in fileReference.media.attributes {
@ -59,7 +59,7 @@ public final class SoftwareVideoLayerFrameManager {
self.layer = layer ?? layerHolder?.layer
self.layer?.videoGravity = .resizeAspectFill
self.layer?.masksToBounds = true
self.fetchDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)).start()
self.fetchDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: fileReference.resourceReference(resource)).start()
}
deinit {

View File

@ -277,9 +277,9 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
if let currentContentImageMedia = currentContentImageMedia, contentImageMedia.isSemanticallyEqual(to: currentContentImageMedia) {
} else {
if let image = contentImageMedia as? TelegramMediaImage {
updateImageSignal = mediaGridMessagePhoto(account: item.context.account, photoReference: .message(message: MessageReference(item.message), media: image))
updateImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: image))
} else if let file = contentImageMedia as? TelegramMediaFile {
updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file), autoFetchFullSizeThumbnail: true)
updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), videoReference: .message(message: MessageReference(item.message), media: file), autoFetchFullSizeThumbnail: true)
}
}
}

View File

@ -188,7 +188,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
if let thumbnail = info.thumbnail {
let signal = Signal<Bool, NoError> { subscriber in
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)).start()
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)).start()
let data = account.postbox.mediaBox.resourceData(thumbnail.resource, option: .incremental(waitUntilFetchStatus: false)).start(next: { data in
if data.complete {
subscriber.putNext(true)
@ -209,10 +209,10 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
for item in topItems {
if item.file.isAnimatedSticker {
let signal = Signal<Bool, NoError> { subscriber in
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start()
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start()
let data = account.postbox.mediaBox.resourceData(item.file.resource).start()
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, file: item.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, userLocation: .other, file: item.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let hasContent = next._0 != nil || next._1 != nil
subscriber.putNext(hasContent)
if hasContent {
@ -289,7 +289,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
public func preloadedStickerPackThumbnail(account: Account, info: StickerPackCollectionInfo, items: [ItemCollectionItem]) -> Signal<Bool, NoError> {
if let thumbnail = info.thumbnail {
let signal = Signal<Bool, NoError> { subscriber in
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)).start()
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)).start()
let dataDisposable: Disposable
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
dataDisposable = chatMessageAnimationData(mediaBox: account.postbox.mediaBox, resource: thumbnail.resource, isVideo: info.flags.contains(.isVideo), width: 80, height: 80, synchronousLoad: false).start(next: { data in
@ -321,10 +321,10 @@ public func preloadedStickerPackThumbnail(account: Account, info: StickerPackCol
if let item = items.first as? StickerPackItem {
if item.file.isAnimatedSticker {
let signal = Signal<Bool, NoError> { subscriber in
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start()
let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start()
let data = account.postbox.mediaBox.resourceData(item.file.resource).start()
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, file: item.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, userLocation: .other, file: item.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let hasContent = next._0 != nil || next._1 != nil
subscriber.putNext(hasContent)
if hasContent {
@ -342,7 +342,7 @@ public func preloadedStickerPackThumbnail(account: Account, info: StickerPackCol
let signal = Signal<Bool, NoError> { subscriber in
let data = account.postbox.mediaBox.resourceData(item.file.resource).start()
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, file: item.file, small: true, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, userLocation: .other, file: item.file, small: true, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in
let hasContent = next._0 != nil || next._1 != nil
subscriber.putNext(hasContent)
if hasContent {

View File

@ -229,9 +229,9 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
if stickerItem.file.isVideoSticker {
self.imageNode.setSignal(chatMessageSticker(account: account, file: stickerItem.file, small: true))
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
} else {
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
}
if self.animationNode == nil {
@ -259,10 +259,10 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode?.visibility = visibility
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
if stickerItem.file.isPremiumSticker, let effect = stickerItem.file.videoThumbnails.first {
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
}
} else {
if let animationNode = self.animationNode {
@ -270,8 +270,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode = nil
animationNode.removeFromSupernode()
}
self.imageNode.setSignal(chatMessageSticker(account: account, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
}
} else {
if isEmpty {

View File

@ -137,7 +137,7 @@ final class StickerPreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black)
break
}
self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false, onlyFullSize: false))
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: item.file, small: false, onlyFullSize: false))
if let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)

View File

@ -130,7 +130,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
animationNode.addSubnode(self.textNode)
if isPremiumSticker, let effect = item.file.videoThumbnails.first {
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: .standalone(media: item.file), resource: effect.resource).start())
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: item.file), resource: effect.resource).start())
let source = AnimatedStickerResourceSource(account: account, resource: effect.resource, fitzModifier: nil)
let additionalAnimationNode = DefaultAnimatedStickerNodeImpl()
@ -143,7 +143,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
self.animationNode = nil
}
self.imageNode.setSignal(chatMessageSticker(account: account, file: item.file, small: false, fetched: true))
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: false, fetched: true))
super.init()

Some files were not shown because too many files have changed in this diff Show More