From 614c74b0b053567d00d09993bfc8425767751327 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 17 Dec 2022 00:17:31 +0400 Subject: [PATCH] [WIP] Modern cache --- .../Sources/NotificationService.swift | 8 + .../Telegram-iOS/en.lproj/Localizable.strings | 4 + .../Sources/FetchMediaUtils.swift | 8 +- .../AttachmentTextInputPanelNode.swift | 2 +- .../Sources/AttachmentController.swift | 4 +- .../Sources/AttachmentPanel.swift | 4 +- .../AvatarNode/Sources/PeerAvatar.swift | 6 +- .../Sources/BotCheckoutControllerNode.swift | 8 +- .../Sources/BotCheckoutHeaderItem.swift | 14 +- .../Sources/BotReceiptControllerNode.swift | 8 +- .../Sources/ChatImportActivityScreen.swift | 2 +- .../Sources/ChatListSearchListPaneNode.swift | 2 +- .../Sources/ChatListSearchMediaNode.swift | 4 +- .../Sources/Node/ChatListItem.swift | 8 +- .../Sources/ReactionButtonListComponent.swift | 1 + .../Sources/ReactionImageComponent.swift | 4 +- .../ReactionListContextMenuContent.swift | 2 + .../Sources/DirectMediaImageCache.swift | 12 +- .../Sources/DrawingStickerEntity.swift | 8 +- .../Sources/FetchManagerImpl.swift | 53 ++- .../GalleryData/Sources/GalleryData.swift | 2 +- .../GalleryUI/Sources/GalleryController.swift | 14 +- .../Items/ChatAnimationGalleryItem.swift | 2 +- .../Items/ChatDocumentGalleryItem.swift | 2 +- .../Items/ChatExternalFileGalleryItem.swift | 2 +- .../Sources/Items/ChatImageGalleryItem.swift | 34 +- .../Items/UniversalVideoGalleryItem.swift | 8 +- .../Sources/InstantImageGalleryItem.swift | 30 +- .../Sources/InstantPageAnchorItem.swift | 2 +- .../Sources/InstantPageArticleItem.swift | 10 +- .../Sources/InstantPageArticleNode.swift | 4 +- .../Sources/InstantPageAudioItem.swift | 2 +- .../Sources/InstantPageContentNode.swift | 8 +- .../Sources/InstantPageController.swift | 18 +- .../Sources/InstantPageControllerNode.swift | 20 +- .../Sources/InstantPageDetailsItem.swift | 4 +- .../Sources/InstantPageDetailsNode.swift | 4 +- .../Sources/InstantPageFeedbackItem.swift | 2 +- .../InstantPageGalleryController.swift | 22 +- .../Sources/InstantPageImageItem.swift | 4 +- .../Sources/InstantPageImageNode.swift | 22 +- .../Sources/InstantPageItem.swift | 2 +- .../Sources/InstantPageLayout.swift | 18 +- .../InstantPagePeerReferenceItem.swift | 2 +- .../InstantPagePlayableVideoItem.swift | 4 +- .../InstantPagePlayableVideoNode.swift | 8 +- .../InstantPageReferenceController.swift | 8 +- .../InstantPageReferenceControllerNode.swift | 8 +- .../Sources/InstantPageShapeItem.swift | 2 +- .../Sources/InstantPageSlideshowItem.swift | 4 +- .../InstantPageSlideshowItemNode.swift | 12 +- .../Sources/InstantPageSubContentNode.swift | 8 +- .../Sources/InstantPageTableItem.swift | 4 +- .../Sources/InstantPageTextItem.swift | 6 +- .../Sources/InstantPageWebEmbedItem.swift | 2 +- .../Sources/ItemListStickerPackItem.swift | 2 +- .../Sources/LegacyAttachmentMenu.swift | 4 +- .../Sources/LegacyAvatarPicker.swift | 2 +- .../Sources/LegacyPaintStickerView.swift | 8 +- .../Sources/LegacyPaintStickersContext.swift | 2 +- .../Sources/ListMessageFileItemNode.swift | 6 +- .../Sources/ListMessageSnippetItemNode.swift | 4 +- .../Sources/FFMpegMediaFrameSource.swift | 12 +- .../FFMpegMediaFrameSourceContext.swift | 18 +- .../MediaPlayer/Sources/MediaPlayer.swift | 12 +- .../Sources/MediaPlayerFramePreview.swift | 12 +- .../Sources/TimeBasedVideoPreload.swift | 4 +- .../UniversalSoftwareVideoSource.swift | 22 +- .../Sources/PeerAvatarImageGalleryItem.swift | 6 +- .../Sources/PeerInfoAvatarListNode.swift | 4 +- .../Sources/GroupStickerPackCurrentItem.swift | 4 +- .../Sources/PhotoResources.swift | 128 ++--- submodules/Postbox/Sources/MediaBox.swift | 198 +++++++- .../Postbox/Sources/MediaResource.swift | 19 +- .../Sources/StorageBox/StorageBox.swift | 88 +++- .../Sources/PhoneDemoComponent.swift | 1 + .../PremiumUI/Sources/PremiumGiftScreen.swift | 6 +- .../Sources/PremiumIntroScreen.swift | 6 +- .../Sources/StickersCarouselComponent.swift | 6 +- .../Sources/ReactionContextNode.swift | 4 +- .../Sources/ReactionSelectionNode.swift | 8 +- .../Sources/SaveToCameraRoll.swift | 15 +- .../Sources/CachedFaqInstantPage.swift | 2 +- .../StorageUsageController.swift | 5 +- .../StorageUsageExceptionsScreen.swift | 32 +- .../Sources/ThemeCarouselItem.swift | 2 +- .../Sources/ThemePickerController.swift | 2 +- .../Sources/ThemePickerGridItem.swift | 2 +- .../Sources/Themes/ThemeGridSearchItem.swift | 2 +- .../Themes/ThemePreviewControllerNode.swift | 2 +- .../Themes/ThemeSettingsController.swift | 2 +- .../Sources/Themes/WallpaperGalleryItem.swift | 8 +- .../Sources/ShareController.swift | 10 +- .../Sources/ShareLoadingContainerNode.swift | 2 +- .../SoftwareVideoLayerFrameManager.swift | 4 +- .../Sources/StatsMessageItem.swift | 4 +- .../StickerPackPreviewController.swift | 14 +- .../Sources/StickerPackPreviewGridItem.swift | 12 +- .../StickerPreviewControllerNode.swift | 2 +- .../Sources/StickerPreviewPeekContent.swift | 4 +- .../Sources/StickerResources.swift | 36 +- .../Sources/PresentationCall.swift | 7 +- .../Sources/Account/Account.swift | 10 + .../Network/FetchedMediaResource.swift | 50 +- .../Sources/Network/MultipartUpload.swift | 2 +- .../Sources/State/AvailableReactions.swift | 2 +- .../TelegramCore/Sources/State/Fetch.swift | 1 + .../Peers/NotificationSoundList.swift | 4 +- .../Resources/CollectCacheUsageStats.swift | 442 ++++++++++-------- .../Resources/TelegramEngineResources.swift | 19 + .../ChatControllerBackgroundNode.swift | 4 +- .../Sources/EmojiStatusComponent.swift | 1 + .../EmojiStatusSelectionComponent.swift | 3 +- .../Sources/EmojiSuggestionsComponent.swift | 2 + .../Sources/EmojiTextAttachmentView.swift | 18 +- .../Sources/EmojiPagerContentComponent.swift | 6 +- .../Sources/GifPagerContentComponent.swift | 10 +- .../Sources/TextNodeWithEntities.swift | 4 +- .../TelegramUI/Sources/AppDelegate.swift | 49 ++ .../Sources/ChatAvatarNavigationNode.swift | 2 +- .../TelegramUI/Sources/ChatBotInfoItem.swift | 5 +- .../ChatContextResultPeekContentNode.swift | 4 +- .../TelegramUI/Sources/ChatController.swift | 54 +-- .../ChatInterfaceStateContextMenus.swift | 2 +- .../ChatMediaInputMetaSectionItemNode.swift | 2 +- .../ChatMediaInputStickerGridItem.swift | 10 +- .../ChatMediaInputStickerPackItem.swift | 2 +- .../Sources/ChatMessageActionItemNode.swift | 6 +- .../ChatMessageAnimatedStickerItemNode.swift | 14 +- .../ChatMessageAttachedContentNode.swift | 2 +- .../Sources/ChatMessageDateHeader.swift | 2 +- .../ChatMessageInteractiveFileNode.swift | 2 +- ...atMessageInteractiveInstantVideoNode.swift | 6 +- .../ChatMessageInteractiveMediaNode.swift | 24 +- .../Sources/ChatMessageNotificationItem.swift | 6 +- ...ageProfilePhotoSuggestionContentNode.swift | 4 +- .../Sources/ChatMessageReplyInfoNode.swift | 6 +- .../Sources/ChatMessageStickerItemNode.swift | 4 +- .../ChatPinnedMessageTitlePanelNode.swift | 10 +- .../TelegramUI/Sources/ChatQrCodeScreen.swift | 14 +- .../ChatRecentActionsControllerNode.swift | 2 +- .../ChatRecordingPreviewInputPanelNode.swift | 4 +- .../Sources/ChatTextInputPanelNode.swift | 3 +- .../TelegramUI/Sources/ChatThemeScreen.swift | 4 +- .../Sources/EditAccessoryPanelNode.swift | 6 +- .../Sources/EmojisChatInputPanelItem.swift | 1 + .../TelegramUI/Sources/GridMessageItem.swift | 4 +- ...ListContextResultsChatInputPanelItem.swift | 8 +- .../Sources/HorizontalStickerGridItem.swift | 10 +- .../Sources/InChatPrefetchManager.swift | 2 +- .../Sources/LargeEmojiActionSheetItem.swift | 4 +- .../Sources/ManagedDiceAnimationNode.swift | 2 +- .../Sources/MediaInputPaneTrendingItem.swift | 10 +- .../Sources/MultiplexedVideoNode.swift | 2 +- .../Sources/NotificationContentContext.swift | 14 +- .../TelegramUI/Sources/OpenChatMessage.swift | 4 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 4 +- .../Panes/PeerInfoVisualMediaPaneNode.swift | 3 + .../Sources/PeerInfo/PeerInfoData.swift | 3 - .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 4 +- .../Sources/PeerInfo/PeerInfoMembers.swift | 18 +- .../Sources/PeerInfoGifPaneNode.swift | 9 +- .../TelegramUI/Sources/PrefetchManager.swift | 4 +- .../Sources/ReplyAccessoryPanelNode.swift | 6 +- .../Sources/SharedMediaPlayer.swift | 6 +- .../Sources/SoftwareVideoThumbnailLayer.swift | 2 +- .../StickerPaneSearchStickerItem.swift | 6 +- .../StickerPaneTrendingListGridItem.swift | 2 +- .../StickersChatInputContextPanelItem.swift | 4 +- .../TelegramUI/Sources/TextLinkHandling.swift | 2 +- .../TransformOutgoingMessageMedia.swift | 4 +- ...ListContextResultsChatInputPanelItem.swift | 4 +- .../Sources/NativeVideoContent.swift | 18 +- .../Sources/PlatformVideoContent.swift | 12 +- .../Sources/SystemVideoContent.swift | 10 +- .../Sources/WebEmbedVideoContent.swift | 10 +- .../Sources/GroupCallContext.swift | 10 +- .../ChannelMemberCategoryListContext.swift | 2 +- ...annelMemberCategoriesContextsManager.swift | 12 + submodules/TgVoipWebrtc/tgcalls | 2 +- .../Sources/UndoOverlayControllerNode.swift | 4 +- .../Sources/WallpaperBackgroundNode.swift | 2 +- .../Sources/WallpaperResources.swift | 14 +- .../Sources/WatchRequestHandlers.swift | 10 +- .../Sources/LegacyWebSearchGallery.swift | 4 +- .../Sources/WebSearchGalleryController.swift | 4 +- .../WebSearchUI/Sources/WebSearchItem.swift | 2 +- .../Sources/WebAppAlertContentNode.swift | 2 +- .../WebUI/Sources/WebAppController.swift | 4 +- 189 files changed, 1464 insertions(+), 848 deletions(-) diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index f697af4b28..67a323248d 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -1142,14 +1142,20 @@ private final class NotificationServiceHandler { var fetchMediaSignal: Signal = .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, diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 1d6ce8211e..20a46f9ad1 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -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."; diff --git a/submodules/AccountContext/Sources/FetchMediaUtils.swift b/submodules/AccountContext/Sources/FetchMediaUtils.swift index 0ce7cc87ea..616bb72f80 100644 --- a/submodules/AccountContext/Sources/FetchMediaUtils.swift +++ b/submodules/AccountContext/Sources/FetchMediaUtils.swift @@ -6,8 +6,8 @@ import SwiftSignalKit import TelegramUIPreferences import RangeSet -public func freeMediaFileInteractiveFetched(account: Account, fileReference: FileMediaReference) -> Signal { - return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)) +public func freeMediaFileInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) -> Signal { + 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 { @@ -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(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 { - return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)) +public func freeMediaFileResourceInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, resource: MediaResource) -> Signal { + return fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(resource)) } public func cancelFreeMediaFileInteractiveFetch(account: Account, file: TelegramMediaFile) { diff --git a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift index 8b3028fd82..22e8301f4a 100644 --- a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift +++ b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift @@ -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) diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 53123bb647..af45bf6514 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -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()) } } } diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 2e6b673402..800a2e141a 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -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() } } } diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index b87ccb76f6..66393e4a84 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -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() diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift index 5e33e8e693..3cc65db389 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift @@ -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?() diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutHeaderItem.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutHeaderItem.swift index 48847922ce..408d932438 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutHeaderItem.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutHeaderItem.swift @@ -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)) } } diff --git a/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift index 137d2fac26..319e8b4e5c 100644 --- a/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift @@ -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, diff --git a/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift b/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift index cd58019495..595a46676b 100644 --- a/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift +++ b/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift @@ -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)) diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index e2f2e6a228..ce39fe83f6 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -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 diff --git a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift index 3772285ee0..af68af53c8 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift @@ -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 diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 87ac307f0b..72e963ad18 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -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 diff --git a/submodules/Components/ReactionButtonListComponent/Sources/ReactionButtonListComponent.swift b/submodules/Components/ReactionButtonListComponent/Sources/ReactionButtonListComponent.swift index a4ef901b9f..35d2f8881a 100644 --- a/submodules/Components/ReactionButtonListComponent/Sources/ReactionButtonListComponent.swift +++ b/submodules/Components/ReactionButtonListComponent/Sources/ReactionButtonListComponent.swift @@ -143,6 +143,7 @@ public final class ReactionIconView: PortalSourceView { let animationLayer = InlineStickerItemLayer( context: context, + userLocation: .other, attemptSynchronousLoad: false, emoji: ChatTextInputTextCustomEmojiAttribute( interactivelySelectedFromPackId: nil, diff --git a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift index 21e6f265ef..db634206d5 100644 --- a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift +++ b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift @@ -19,7 +19,7 @@ public let sharedReactionStaticImage = Queue(name: "SharedReactionStaticImage", public func reactionStaticImage(context: AccountContext, animation: TelegramMediaFile, pixelSize: CGSize, queue: Queue) -> Signal { 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 diff --git a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift index 9a52a5229c..88fbc0a261 100644 --- a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift +++ b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift @@ -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, diff --git a/submodules/DirectMediaImageCache/Sources/DirectMediaImageCache.swift b/submodules/DirectMediaImageCache/Sources/DirectMediaImageCache.swift index 57ee73149c..268671d2a2 100644 --- a/submodules/DirectMediaImageCache/Sources/DirectMediaImageCache.swift +++ b/submodules/DirectMediaImageCache/Sources/DirectMediaImageCache.swift @@ -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? { + private func getLoadSignal(width: Int, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resource: MediaResourceReference, resourceSizeLimit: Int64) -> Signal? { 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() diff --git a/submodules/DrawingUI/Sources/DrawingStickerEntity.swift b/submodules/DrawingUI/Sources/DrawingStickerEntity.swift index f591097401..38e762eaea 100644 --- a/submodules/DrawingUI/Sources/DrawingStickerEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingStickerEntity.swift @@ -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 diff --git a/submodules/FetchManagerImpl/Sources/FetchManagerImpl.swift b/submodules/FetchManagerImpl/Sources/FetchManagerImpl.swift index a257e4a7fb..6111fff551 100644 --- a/submodules/FetchManagerImpl/Sources/FetchManagerImpl.swift +++ b/submodules/FetchManagerImpl/Sources/FetchManagerImpl.swift @@ -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 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 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() diff --git a/submodules/GalleryData/Sources/GalleryData.swift b/submodules/GalleryData/Sources/GalleryData.swift index 7af4708784..c32141d3ff 100644 --- a/submodules/GalleryData/Sources/GalleryData.swift +++ b/submodules/GalleryData/Sources/GalleryData.swift @@ -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) } diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 12283c5772..785185bd0e 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -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 diff --git a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift index aa61b12e7b..3f421393a7 100644 --- a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift @@ -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 } diff --git a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift index b44a9336c5..28a519f424 100644 --- a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift @@ -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 } diff --git a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift index aab16e3fa9..54cb1eeeed 100644 --- a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift @@ -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 } diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 1d5f95c3de..d177481c66 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -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 } diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index b061a38700..a6689b104a 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -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 diff --git a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift index 34845f3f13..d397279f8a 100644 --- a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift +++ b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift @@ -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() 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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageAnchorItem.swift b/submodules/InstantPageUI/Sources/InstantPageAnchorItem.swift index 5356646d0d..5716720974 100644 --- a/submodules/InstantPageUI/Sources/InstantPageAnchorItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageAnchorItem.swift @@ -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 } diff --git a/submodules/InstantPageUI/Sources/InstantPageArticleItem.swift b/submodules/InstantPageUI/Sources/InstantPageArticleItem.swift index f83b6ab86f..fb1b3f3f77 100644 --- a/submodules/InstantPageUI/Sources/InstantPageArticleItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageArticleItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageArticleNode.swift b/submodules/InstantPageUI/Sources/InstantPageArticleNode.swift index 7bde8c039c..a13a3099d5 100644 --- a/submodules/InstantPageUI/Sources/InstantPageArticleNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageArticleNode.swift @@ -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) diff --git a/submodules/InstantPageUI/Sources/InstantPageAudioItem.swift b/submodules/InstantPageUI/Sources/InstantPageAudioItem.swift index 21fded36a4..8a2ed3c11c 100644 --- a/submodules/InstantPageUI/Sources/InstantPageAudioItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageAudioItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageContentNode.swift b/submodules/InstantPageUI/Sources/InstantPageContentNode.swift index 5d342c96a7..999ba1d5bb 100644 --- a/submodules/InstantPageUI/Sources/InstantPageContentNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageContentNode.swift @@ -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) diff --git a/submodules/InstantPageUI/Sources/InstantPageController.swift b/submodules/InstantPageUI/Sources/InstantPageController.swift index 05cabd89dd..25cb5dcf64 100644 --- a/submodules/InstantPageUI/Sources/InstantPageController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageController.swift @@ -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) diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index 63beac8e35..d66c110f82 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPageDetailsItem.swift b/submodules/InstantPageUI/Sources/InstantPageDetailsItem.swift index 9d610105b7..f567bbe326 100644 --- a/submodules/InstantPageUI/Sources/InstantPageDetailsItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageDetailsItem.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPageDetailsNode.swift b/submodules/InstantPageUI/Sources/InstantPageDetailsNode.swift index a65e0dc7b4..2cf212786d 100644 --- a/submodules/InstantPageUI/Sources/InstantPageDetailsNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageDetailsNode.swift @@ -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() diff --git a/submodules/InstantPageUI/Sources/InstantPageFeedbackItem.swift b/submodules/InstantPageUI/Sources/InstantPageFeedbackItem.swift index 122c8e0702..7bdb399ccf 100644 --- a/submodules/InstantPageUI/Sources/InstantPageFeedbackItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageFeedbackItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index a54d01f437..716aef66b4 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -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?) -> 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?) -> 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 diff --git a/submodules/InstantPageUI/Sources/InstantPageImageItem.swift b/submodules/InstantPageUI/Sources/InstantPageImageItem.swift index 05aae91fd3..a08814737c 100644 --- a/submodules/InstantPageUI/Sources/InstantPageImageItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageImageItem.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPageImageNode.swift b/submodules/InstantPageUI/Sources/InstantPageImageNode.swift index f7ceffea21..0aeea7c501 100644 --- a/submodules/InstantPageUI/Sources/InstantPageImageNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageImageNode.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageItem.swift b/submodules/InstantPageUI/Sources/InstantPageItem.swift index 0ef9bc2226..6804e8bc44 100644 --- a/submodules/InstantPageUI/Sources/InstantPageItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageItem.swift @@ -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] diff --git a/submodules/InstantPageUI/Sources/InstantPageLayout.swift b/submodules/InstantPageUI/Sources/InstantPageLayout.swift index 4f157f5e4f..3647452673 100644 --- a/submodules/InstantPageUI/Sources/InstantPageLayout.swift +++ b/submodules/InstantPageUI/Sources/InstantPageLayout.swift @@ -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) diff --git a/submodules/InstantPageUI/Sources/InstantPagePeerReferenceItem.swift b/submodules/InstantPageUI/Sources/InstantPagePeerReferenceItem.swift index 3c2a91b33d..0bc839724f 100644 --- a/submodules/InstantPageUI/Sources/InstantPagePeerReferenceItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPagePeerReferenceItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPagePlayableVideoItem.swift b/submodules/InstantPageUI/Sources/InstantPagePlayableVideoItem.swift index a68ae01c39..79a32538c3 100644 --- a/submodules/InstantPageUI/Sources/InstantPagePlayableVideoItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPagePlayableVideoItem.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPagePlayableVideoNode.swift b/submodules/InstantPageUI/Sources/InstantPagePlayableVideoNode.swift index 86b0921dce..dc63946e03 100644 --- a/submodules/InstantPageUI/Sources/InstantPagePlayableVideoNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPagePlayableVideoNode.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift b/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift index 825827066b..64860688c0 100644 --- a/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageReferenceController.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageReferenceControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageReferenceControllerNode.swift index 548b6abe1a..3a13d373cb 100644 --- a/submodules/InstantPageUI/Sources/InstantPageReferenceControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageReferenceControllerNode.swift @@ -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 diff --git a/submodules/InstantPageUI/Sources/InstantPageShapeItem.swift b/submodules/InstantPageUI/Sources/InstantPageShapeItem.swift index a1703ed3ff..b5b354686f 100644 --- a/submodules/InstantPageUI/Sources/InstantPageShapeItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageShapeItem.swift @@ -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 } diff --git a/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift b/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift index 2d19757b57..d9e081d15c 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSlideshowItem.swift @@ -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 { diff --git a/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift b/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift index a45ee2f1eb..3449b27727 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSlideshowItemNode.swift @@ -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)) diff --git a/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift b/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift index 89b4ab0e93..d8146a8b30 100644 --- a/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageSubContentNode.swift @@ -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) diff --git a/submodules/InstantPageUI/Sources/InstantPageTableItem.swift b/submodules/InstantPageUI/Sources/InstantPageTableItem.swift index 4188955b66..fe99459868 100644 --- a/submodules/InstantPageUI/Sources/InstantPageTableItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageTableItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageTextItem.swift b/submodules/InstantPageUI/Sources/InstantPageTextItem.swift index d1c9287ecd..e707cc6b53 100644 --- a/submodules/InstantPageUI/Sources/InstantPageTextItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageTextItem.swift @@ -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) } diff --git a/submodules/InstantPageUI/Sources/InstantPageWebEmbedItem.swift b/submodules/InstantPageUI/Sources/InstantPageWebEmbedItem.swift index 71d24dc6d8..4292366e7a 100644 --- a/submodules/InstantPageUI/Sources/InstantPageWebEmbedItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageWebEmbedItem.swift @@ -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) } diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 3d1133a361..1f437162bb 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -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 }) diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index 2e11b4d5e6..ef488a9756 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -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 diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift index 8e97fffc79..c4bee5231a 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift @@ -54,7 +54,7 @@ public func presentLegacyAvatarPicker(holder: Atomic, 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 diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift index 8b22cdf638..42a3920db1 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift @@ -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 diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift index 24e00747b3..26b30357f2 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift @@ -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())) diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index 4255c26a84..6663053c28 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -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() diff --git a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift index 8e7e91f46e..3fbdc9dea6 100644 --- a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift @@ -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() diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSource.swift b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSource.swift index 6d37744bb5..9df8abd8f4 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSource.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSource.swift @@ -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 { diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift index 289175dd5c..3a255009f2 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift @@ -196,7 +196,7 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whence: Int32) -> Int64 { let context = Unmanaged.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 = 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 } diff --git a/submodules/MediaPlayer/Sources/MediaPlayer.swift b/submodules/MediaPlayer/Sources/MediaPlayer.swift index e1ab42f53f..f33b11fbaf 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayer.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayer.swift @@ -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, audioLevelPipe: ValuePipe, 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, audioLevelPipe: ValuePipe, 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) } } diff --git a/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift index 47730aaa06..b67019af30 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift @@ -25,9 +25,9 @@ private final class FramePreviewContext { } } -private func initializedPreviewContext(queue: Queue, postbox: Postbox, fileReference: FileMediaReference) -> Signal, NoError> { +private func initializedPreviewContext(queue: Queue, postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference) -> Signal, 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() - 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) }) } diff --git a/submodules/MediaPlayer/Sources/TimeBasedVideoPreload.swift b/submodules/MediaPlayer/Sources/TimeBasedVideoPreload.swift index bdd451b19b..f9abf15ea0 100644 --- a/submodules/MediaPlayer/Sources/TimeBasedVideoPreload.swift +++ b/submodules/MediaPlayer/Sources/TimeBasedVideoPreload.swift @@ -5,14 +5,14 @@ import Postbox import TelegramCore import FFMpegBinding -public func preloadVideoResource(postbox: Postbox, resourceReference: MediaResourceReference, duration: Double) -> Signal { +public func preloadVideoResource(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resourceReference: MediaResourceReference, duration: Double) -> Signal { 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 }) diff --git a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift index 12c3fc1bd9..741d9a3647 100644 --- a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift +++ b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift @@ -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, cancelInitialization: Signal, automaticallyFetchHeader: Bool, hintVP9: Bool = false) { + init?(mediaBox: MediaBox, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, fileReference: FileMediaReference, state: ValuePromise, cancelInitialization: Signal, 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 let cancelInitialization: Signal @@ -297,6 +305,8 @@ private final class UniversalSoftwareVideoSourceThreadParams: NSObject { init( mediaBox: MediaBox, + userLocation: MediaResourceUserLocation, + userContentType: MediaResourceUserContentType, fileReference: FileMediaReference, state: ValuePromise, cancelInitialization: Signal, @@ -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() } diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 7e5d6a386c..536e0d421e 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -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 diff --git a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift index 4c54231775..71d66e8810 100644 --- a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift +++ b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift @@ -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 diff --git a/submodules/PeerInfoUI/Sources/GroupStickerPackCurrentItem.swift b/submodules/PeerInfoUI/Sources/GroupStickerPackCurrentItem.swift index c57094dd24..2f32d43117 100644 --- a/submodules/PeerInfoUI/Sources/GroupStickerPackCurrentItem.swift +++ b/submodules/PeerInfoUI/Sources/GroupStickerPackCurrentItem.swift @@ -232,8 +232,8 @@ class GroupStickerPackCurrentItemNode: ItemListRevealOptionsItemNode { var updatedFetchSignal: Signal? 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() diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index 4644c26452..2513437ef7 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -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, 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, 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, NoError> { +private func chatMessageFileDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, fetched: Bool = false) -> Signal, 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 = Set([ "image/heic" ]) -private func chatMessageImageFileThumbnailDatas(account: Account, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal, NoError> { +private func chatMessageImageFileThumbnailDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, autoFetchFullSizeThumbnail: Bool = false) -> Signal, 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 = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource)) + let fetchedThumbnail: Signal = 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?, 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?, 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 { - return chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference, autoFetchFullSize: true) +public func rawMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal { + 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 Signal, NoError> { +private func chatMessagePhotoThumbnailDatas(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal, 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 { 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 { 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?, 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?, 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 { +public func standaloneChatMessagePhotoInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal { 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 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 { +public func chatMessagePhotoInteractiveFetched(context: AccountContext, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, displayAtSize: Int?, storeToDownloadsPeerType: MediaAutoDownloadPeerType?) -> Signal { if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) { var fetchRange: (Range, 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 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 { - return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: image.resource), statsCategory: .image) +public func chatMessageWebFileInteractiveFetched(account: Account, userLocation: MediaResourceUserLocation, image: TelegramMediaWebFile) -> Signal { + 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 { +public func chatWebpageSnippetFileData(account: Account, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference, resource: MediaResource) -> Signal { 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 { +public func chatWebpageSnippetPhotoData(account: Account, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference) -> Signal { 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 { +private func chatSecretMessageVideoData(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) -> Signal { 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, 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 { 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 { subscriber in let fetchedDisposable = fetchedThumbnail.start() diff --git a/submodules/Postbox/Sources/MediaBox.swift b/submodules/Postbox/Sources/MediaBox.swift index e571086051..495a31a679 100644 --- a/submodules/Postbox/Sources/MediaBox.swift +++ b/submodules/Postbox/Sources/MediaBox.swift @@ -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? + private let pathBuffer: UnsafeMutablePointer + + 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 +}*/ diff --git a/submodules/Postbox/Sources/MediaResource.swift b/submodules/Postbox/Sources/MediaResource.swift index e72385f7a2..70eca992a6 100644 --- a/submodules/Postbox/Sources/MediaResource.swift +++ b/submodules/Postbox/Sources/MediaResource.swift @@ -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 } } diff --git a/submodules/Postbox/Sources/StorageBox/StorageBox.swift b/submodules/Postbox/Sources/StorageBox/StorageBox.swift index 3fb83de136..74cfa1267a 100644 --- a/submodules/Postbox/Sources/StorageBox/StorageBox.swift +++ b/submodules/Postbox/Sources/StorageBox/StorageBox.swift @@ -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) diff --git a/submodules/PremiumUI/Sources/PhoneDemoComponent.swift b/submodules/PremiumUI/Sources/PhoneDemoComponent.swift index 5ffa1162f2..67d014e552 100644 --- a/submodules/PremiumUI/Sources/PhoneDemoComponent.swift +++ b/submodules/PremiumUI/Sources/PhoneDemoComponent.swift @@ -165,6 +165,7 @@ private final class PhoneView: UIView { let videoContent = NativeVideoContent( id: .message(1, MediaId(namespace: 0, id: Int64.random(in: 0.. 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, diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift index 66ef9faa12..e9b261aa05 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift @@ -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() } } diff --git a/submodules/SaveToCameraRoll/Sources/SaveToCameraRoll.swift b/submodules/SaveToCameraRoll/Sources/SaveToCameraRoll.swift index d059463f7a..d1f948ed2f 100644 --- a/submodules/SaveToCameraRoll/Sources/SaveToCameraRoll.swift +++ b/submodules/SaveToCameraRoll/Sources/SaveToCameraRoll.swift @@ -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 = 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 { - return fetchMediaData(context: context, postbox: postbox, mediaReference: mediaReference) +public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal { + return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, mediaReference: mediaReference) |> mapToSignal { state, isImage -> Signal 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 { - return fetchMediaData(context: context, postbox: postbox, mediaReference: mediaReference) +public func copyToPasteboard(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal { + return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, mediaReference: mediaReference) |> mapToSignal { state, isImage -> Signal in if case let .data(data) = state, data.complete { return Signal { subscriber in diff --git a/submodules/SettingsUI/Sources/CachedFaqInstantPage.swift b/submodules/SettingsUI/Sources/CachedFaqInstantPage.swift index 93671bb8e0..58f145fd42 100644 --- a/submodules/SettingsUI/Sources/CachedFaqInstantPage.swift +++ b/submodules/SettingsUI/Sources/CachedFaqInstantPage.swift @@ -47,7 +47,7 @@ func faqSearchableItems(context: AccountContext, resolvedUrl: Signal [(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 } diff --git a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageExceptionsScreen.swift b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageExceptionsScreen.swift index 63fdca9fd6..9f44b03970 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageExceptionsScreen.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageExceptionsScreen.swift @@ -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 diff --git a/submodules/SettingsUI/Sources/ThemeCarouselItem.swift b/submodules/SettingsUI/Sources/ThemeCarouselItem.swift index 9a54263bb5..a03e7dbd82 100644 --- a/submodules/SettingsUI/Sources/ThemeCarouselItem.swift +++ b/submodules/SettingsUI/Sources/ThemeCarouselItem.swift @@ -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) diff --git a/submodules/SettingsUI/Sources/ThemePickerController.swift b/submodules/SettingsUI/Sources/ThemePickerController.swift index 776f0b226d..9aee46a7ae 100644 --- a/submodules/SettingsUI/Sources/ThemePickerController.swift +++ b/submodules/SettingsUI/Sources/ThemePickerController.swift @@ -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) diff --git a/submodules/SettingsUI/Sources/ThemePickerGridItem.swift b/submodules/SettingsUI/Sources/ThemePickerGridItem.swift index 9f0b344c82..54fd2d9aff 100644 --- a/submodules/SettingsUI/Sources/ThemePickerGridItem.swift +++ b/submodules/SettingsUI/Sources/ThemePickerGridItem.swift @@ -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) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchItem.swift index 889464867d..12e53a36db 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchItem.swift @@ -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() } diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index ae0325e94b..c1724ac735 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -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) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 7ab7c169d1..e80a8336a2 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -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) diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift index 5674096da7..dc19067e95 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift @@ -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) diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index fa47274f40..ccb9c4f094 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -87,7 +87,7 @@ private enum ExternalShareResourceStatus { private func collectExternalShareResource(postbox: Postbox, resourceReference: MediaResourceReference, statsCategory: MediaResourceStatsCategory) -> Signal { 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) { diff --git a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift index 7c9589592b..f4e07f5ef3 100644 --- a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift +++ b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift @@ -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)) diff --git a/submodules/SoftwareVideo/Sources/SoftwareVideoLayerFrameManager.swift b/submodules/SoftwareVideo/Sources/SoftwareVideoLayerFrameManager.swift index 0e7d528b9f..7353213b80 100644 --- a/submodules/SoftwareVideo/Sources/SoftwareVideoLayerFrameManager.swift +++ b/submodules/SoftwareVideo/Sources/SoftwareVideoLayerFrameManager.swift @@ -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 { diff --git a/submodules/StatisticsUI/Sources/StatsMessageItem.swift b/submodules/StatisticsUI/Sources/StatsMessageItem.swift index a3725e2a84..b76ff08fa2 100644 --- a/submodules/StatisticsUI/Sources/StatsMessageItem.swift +++ b/submodules/StatisticsUI/Sources/StatsMessageItem.swift @@ -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) } } } diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift index 5e3e66a6c6..3b56f2e42e 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift @@ -188,7 +188,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese if let thumbnail = info.thumbnail { let signal = Signal { 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 { 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 { if let thumbnail = info.thumbnail { let signal = Signal { 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 { 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 { 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 { diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift index 8849783d9b..b081b5cf5b 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift @@ -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 { diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift index a0f91ddc6f..66850c8f93 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift @@ -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) diff --git a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift index 1eeef0f26a..088e5b6443 100644 --- a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift +++ b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift @@ -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() diff --git a/submodules/StickerResources/Sources/StickerResources.swift b/submodules/StickerResources/Sources/StickerResources.swift index 4e89fa8e74..815840466b 100644 --- a/submodules/StickerResources/Sources/StickerResources.swift +++ b/submodules/StickerResources/Sources/StickerResources.swift @@ -48,7 +48,7 @@ public func chatMessageStickerResource(file: TelegramMediaFile, small: Bool) -> return resource } -private func chatMessageStickerDatas(postbox: Postbox, file: TelegramMediaFile, small: Bool, fetched: Bool, onlyFullSize: Bool, synchronousLoad: Bool) -> Signal, NoError> { +private func chatMessageStickerDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool, onlyFullSize: Bool, synchronousLoad: Bool) -> Signal, NoError> { let thumbnailResource = chatMessageStickerResource(file: file, small: true) let resource = chatMessageStickerResource(file: file, small: small) @@ -71,12 +71,12 @@ private func chatMessageStickerDatas(postbox: Postbox, file: TelegramMediaFile, return Signal { subscriber in var fetch: Disposable? if fetched { - fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(resource)).start() + fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(resource)).start() } var fetchThumbnail: Disposable? if thumbnailResource.id != resource.id { - fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() } let disposable = (combineLatest(thumbnailData, fullSizeData) |> map { thumbnailData, fullSizeData -> Tuple3 in @@ -98,7 +98,7 @@ private func chatMessageStickerDatas(postbox: Postbox, file: TelegramMediaFile, } } -public func chatMessageAnimatedStickerDatas(postbox: Postbox, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool, onlyFullSize: Bool, synchronousLoad: Bool) -> Signal, NoError> { +public func chatMessageAnimatedStickerDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool, onlyFullSize: Bool, synchronousLoad: Bool) -> Signal, NoError> { let thumbnailResource = chatMessageStickerResource(file: file, small: true) let resource = chatMessageStickerResource(file: file, small: false) @@ -122,12 +122,12 @@ public func chatMessageAnimatedStickerDatas(postbox: Postbox, file: TelegramMedi return Signal { subscriber in var fetch: Disposable? if fetched { - fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(resource)).start() + fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(resource)).start() } var fetchThumbnail: Disposable? if thumbnailResource.id != resource.id { - fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() } let disposable = (combineLatest(thumbnailData, fullSizeData) |> map { thumbnailData, fullSizeData -> Tuple3 in @@ -149,7 +149,7 @@ public func chatMessageAnimatedStickerDatas(postbox: Postbox, file: TelegramMedi } } -private func chatMessageStickerThumbnailData(postbox: Postbox, file: TelegramMediaFile, synchronousLoad: Bool) -> Signal { +private func chatMessageStickerThumbnailData(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, synchronousLoad: Bool) -> Signal { let thumbnailResource = chatMessageStickerResource(file: file, small: true) let maybeFetched = postbox.mediaBox.cachedResourceRepresentation(thumbnailResource, representation: CachedStickerAJpegRepresentation(size: nil), complete: false, fetch: false, attemptSynchronously: synchronousLoad) @@ -164,7 +164,7 @@ private func chatMessageStickerThumbnailData(postbox: Postbox, file: TelegramMed let thumbnailData = postbox.mediaBox.cachedResourceRepresentation(thumbnailResource, representation: CachedStickerAJpegRepresentation(size: nil), complete: false) return Signal { subscriber in - let fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + let fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .sticker, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() let disposable = (thumbnailData |> map { thumbnailData -> Data? in @@ -259,8 +259,8 @@ public func chatMessageAnimatedStickerBackingData(postbox: Postbox, fileReferenc } } -public func chatMessageLegacySticker(account: Account, file: TelegramMediaFile, small: Bool, fitSize: CGSize, fetched: Bool = false, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - let signal = chatMessageStickerDatas(postbox: account.postbox, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: false) +public func chatMessageLegacySticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fitSize: CGSize, fetched: Bool = false, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + let signal = chatMessageStickerDatas(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: false) return signal |> map { value in let fullSizeData = value._1 let fullSizeComplete = value._2 @@ -328,8 +328,8 @@ public func chatMessageLegacySticker(account: Account, file: TelegramMediaFile, } } -public func chatMessageSticker(account: Account, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - return chatMessageSticker(postbox: account.postbox, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, thumbnail: thumbnail, synchronousLoad: synchronousLoad) +public func chatMessageSticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + return chatMessageSticker(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, thumbnail: thumbnail, synchronousLoad: synchronousLoad) } public func chatMessageStickerPackThumbnail(postbox: Postbox, resource: MediaResource, animated: Bool = false, synchronousLoad: Bool = false, nilIfEmpty: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { @@ -385,15 +385,15 @@ public func chatMessageStickerPackThumbnail(postbox: Postbox, resource: MediaRes } } -public func chatMessageSticker(postbox: Postbox, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { +public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { let signal: Signal, NoError> if thumbnail { - signal = chatMessageStickerThumbnailData(postbox: postbox, file: file, synchronousLoad: synchronousLoad) + signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad) |> map { data -> Tuple3in return Tuple3(data, nil, false) } } else { - signal = chatMessageStickerDatas(postbox: postbox, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad) + signal = chatMessageStickerDatas(postbox: postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad) } return signal |> map { value in let thumbnailData = value._0 @@ -486,15 +486,15 @@ public func chatMessageSticker(postbox: Postbox, file: TelegramMediaFile, small: } } -public func chatMessageAnimatedSticker(postbox: Postbox, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { +public func chatMessageAnimatedSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { let signal: Signal, NoError> if thumbnail { - signal = chatMessageStickerThumbnailData(postbox: postbox, file: file, synchronousLoad: synchronousLoad) + signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad) |> map { data -> Tuple3 in return Tuple(data, nil, false) } } else { - signal = chatMessageAnimatedStickerDatas(postbox: postbox, file: file, small: small, size: size, fitzModifier: fitzModifier, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad) + signal = chatMessageAnimatedStickerDatas(postbox: postbox, userLocation: userLocation, file: file, small: small, size: size, fitzModifier: fitzModifier, fetched: fetched, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad) } return signal |> map { value in diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index bfee657104..470c190e16 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -85,6 +85,7 @@ public final class PresentationCallImpl: PresentationCall { private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil)) private var audioOutputStateValue: ([AudioSessionOutput], AudioSessionOutput?) = ([], nil) private var currentAudioOutputValue: AudioSessionOutput = .builtin + private var didSetCurrentAudioOutputValue: Bool = false public var audioOutputState: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> { return self.audioOutputStatePromise.get() } @@ -242,6 +243,7 @@ public final class PresentationCallImpl: PresentationCall { strongSelf.audioOutputStateValue = (availableOutputs, currentOutput) if let currentOutput = currentOutput { strongSelf.currentAudioOutputValue = currentOutput + strongSelf.didSetCurrentAudioOutputValue = true } var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput)) @@ -371,7 +373,9 @@ public final class PresentationCallImpl: PresentationCall { if let audioSessionControl = audioSessionControl, previous == nil || previousControl == nil { if let callKitIntegration = self.callKitIntegration { - callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) + if self.didSetCurrentAudioOutputValue { + callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) + } } else { audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue)) audioSessionControl.setup(synchronous: true) @@ -868,6 +872,7 @@ public final class PresentationCallImpl: PresentationCall { return } self.currentAudioOutputValue = output + self.didSetCurrentAudioOutputValue = true self.audioOutputStatePromise.set(.single((self.audioOutputStateValue.0, output)) |> then( diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index ece6277ef4..cb7a162ad5 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -1280,6 +1280,16 @@ public class Account { self.viewTracker.reset() } + public func cleanupTasks() -> Signal { + let postbox = self.postbox + + return Signal { subscriber in + return postbox.mediaBox.updateResourceIndex(completion: { + subscriber.putCompletion() + }) + } + } + public func restartContactManagement() { self.contactSyncManager.beginSync(importableContacts: self.importableContacts.get()) } diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index d13287e4ce..e08185c6e6 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -25,31 +25,61 @@ final class TelegramCloudMediaResourceFetchInfo: MediaResourceFetchInfo { } } -public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceReference, range: (Range, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { - return fetchedMediaResource(mediaBox: mediaBox, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground) +public func fetchedMediaResource( + mediaBox: MediaBox, + userLocation: MediaResourceUserLocation, + userContentType: MediaResourceUserContentType, + reference: MediaResourceReference, + range: (Range, MediaBoxFetchPriority)? = nil, + statsCategory: MediaResourceStatsCategory = .generic, + reportResultStatus: Bool = false, + preferBackgroundReferenceRevalidation: Bool = false, + continueInBackground: Bool = false +) -> Signal { + return fetchedMediaResource(mediaBox: mediaBox, userLocation: userLocation, userContentType: userContentType, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground) } public extension MediaResourceStorageLocation { - convenience init?(reference: MediaResourceReference) { + convenience init?(userLocation: MediaResourceUserLocation, reference: MediaResourceReference) { switch reference { case let .media(media, _): switch media { case let .message(message, _): if let id = message.id { self.init(peerId: id.peerId, messageId: id) - } else { - return nil } default: - return nil + break } default: + break + } + + switch userLocation { + case let .peer(id): + self.init(peerId: id, messageId: nil) + case .other: return nil } } } -public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceReference, ranges: [(Range, MediaBoxFetchPriority)]?, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { +public enum MediaResourceUserLocation: Equatable { + case peer(EnginePeer.Id) + case other +} + +public func fetchedMediaResource( + mediaBox: MediaBox, + userLocation: MediaResourceUserLocation, + userContentType: MediaResourceUserContentType, + reference: MediaResourceReference, + ranges: [(Range, MediaBoxFetchPriority)]?, + statsCategory: MediaResourceStatsCategory = .generic, + reportResultStatus: Bool = false, + preferBackgroundReferenceRevalidation: Bool = false, + continueInBackground: Bool = false +) -> Signal { var isRandomAccessAllowed = true switch reference { case let .media(media, _): @@ -67,7 +97,8 @@ public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceRef return mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters( tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground), - location: MediaResourceStorageLocation(reference: reference), + location: MediaResourceStorageLocation(userLocation: userLocation, reference: reference), + contentType: userContentType, isRandomAccessAllowed: isRandomAccessAllowed )) } @@ -79,7 +110,8 @@ public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceRef return mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters( tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground), - location: MediaResourceStorageLocation(reference: reference), + location: MediaResourceStorageLocation(userLocation: userLocation, reference: reference), + contentType: userContentType, isRandomAccessAllowed: isRandomAccessAllowed ), implNext: reportResultStatus) } diff --git a/submodules/TelegramCore/Sources/Network/MultipartUpload.swift b/submodules/TelegramCore/Sources/Network/MultipartUpload.swift index 33cd82d133..53b79f1e65 100644 --- a/submodules/TelegramCore/Sources/Network/MultipartUpload.swift +++ b/submodules/TelegramCore/Sources/Network/MultipartUpload.swift @@ -433,7 +433,7 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload case let .resource(resource): dataSignal = postbox.mediaBox.resourceData(resource.resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) } headerSize = resource.resource.headerSize - fetchedResource = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resource) + fetchedResource = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .other, reference: resource) |> map { _ in } case let .tempFile(file): if let size = fileSize(file.path) { diff --git a/submodules/TelegramCore/Sources/State/AvailableReactions.swift b/submodules/TelegramCore/Sources/State/AvailableReactions.swift index 7f88ae2e7f..7476c2374f 100644 --- a/submodules/TelegramCore/Sources/State/AvailableReactions.swift +++ b/submodules/TelegramCore/Sources/State/AvailableReactions.swift @@ -313,7 +313,7 @@ func managedSynchronizeAvailableReactions(postbox: Postbox, network: Network) -> for resource in resources { signals.append( - fetchedMediaResource(mediaBox: postbox.mediaBox, reference: .standalone(resource: resource)) + fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .standalone(resource: resource)) |> ignoreValues |> `catch` { _ -> Signal in return .complete() diff --git a/submodules/TelegramCore/Sources/State/Fetch.swift b/submodules/TelegramCore/Sources/State/Fetch.swift index 7ec872f6b6..5e65c43197 100644 --- a/submodules/TelegramCore/Sources/State/Fetch.swift +++ b/submodules/TelegramCore/Sources/State/Fetch.swift @@ -79,6 +79,7 @@ func fetchResource(account: Account, resource: MediaResource, intervals: Signal< tag: nil, info: TelegramCloudMediaResourceFetchInfo(reference: .standalone(resource: file.file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), location: nil, + contentType: .other, isRandomAccessAllowed: true ))) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift index 4b2847d778..77238d619d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift @@ -152,7 +152,7 @@ public func ensureDownloadedNotificationSoundList(postbox: Postbox) -> Signal ignoreValues |> `catch` { _ -> Signal in return .complete() @@ -228,7 +228,7 @@ private func pollNotificationSoundList(postbox: Postbox, network: Network) -> Si for resource in resources { signals.append( - fetchedMediaResource(mediaBox: postbox.mediaBox, reference: .soundList(resource: resource)) + fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .file, reference: .soundList(resource: resource)) |> ignoreValues |> `catch` { _ -> Signal in return .complete() diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift index 1f9542ead2..57f6587388 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift @@ -53,204 +53,258 @@ private final class CacheUsageStatsState { } func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, additionalCachePaths: [String] = [], logFilesPath: String? = nil) -> Signal { - if "".isEmpty { - return account.postbox.mediaBox.collectAllResourceUsage() - |> mapToSignal { resourceList -> Signal in - return account.postbox.mediaBox.storageBox.get(ids: resourceList.compactMap { item -> Data? in - return item.id?.data(using: .utf8) - }) - |> mapToSignal { entries -> Signal in - return account.postbox.transaction { transaction -> CacheUsageStatsResult in - var media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]] = [:] - var mediaResourceIds: [MediaId: [MediaResourceId]] = [:] - - media.removeAll() - mediaResourceIds.removeAll() - - let mediaBox = account.postbox.mediaBox - - var totalSize: Int64 = 0 - var mediaSize: Int64 = 0 - - var processedResourceIds = Set() - - for entry in entries { - let resourceId = MediaResourceId(String(data: entry.id, encoding: .utf8)!) - let resourceSize = mediaBox.resourceUsage(id: resourceId) - if resourceSize != 0 { - totalSize += resourceSize - - for reference in entry.references { - if let message = transaction.getMessage(MessageId(peerId: PeerId(reference.peerId), namespace: MessageId.Namespace(reference.messageNamespace), id: reference.messageId)) { - for mediaItem in message.media { - guard let mediaId = mediaItem.id else { - continue - } - var category: PeerCacheUsageCategory? - if let _ = mediaItem as? TelegramMediaImage { - category = .image - } else if let mediaItem = mediaItem as? TelegramMediaFile { - if mediaItem.isMusic || mediaItem.isVoice { - category = .audio - } else if mediaItem.isVideo { - category = .video - } else { - category = .file - } - } - if let category = category { - mediaSize += resourceSize - processedResourceIds.insert(resourceId.stringRepresentation) - - media[PeerId(reference.peerId), default: [:]][category, default: [:]][mediaId, default: 0] += resourceSize - if let index = mediaResourceIds.index(forKey: mediaId) { - if !mediaResourceIds[index].value.contains(resourceId) { - mediaResourceIds[mediaId]?.append(resourceId) - } - } else { - mediaResourceIds[mediaId] = [resourceId] - } - } - } - } - } - } - } - - var peers: [PeerId: Peer] = [:] - for peerId in media.keys { - if let peer = transaction.getPeer(peerId) { - peers[peer.id] = peer - } - } - - var tempPaths: [String] = [] - var tempSize: Int64 = 0 - #if os(iOS) - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: NSTemporaryDirectory()), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { - for url in enumerator { - if let url = url as? URL { - if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { - tempPaths.append(url.path) - } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { - tempPaths.append(url.path) - - if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { - } else { - tempSize += Int64(fileSizeValue) - } - } - } - } - } - #endif - - var immutableSize: Int64 = 0 - if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: account.basePath + "/postbox/db"), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { - for url in files { - if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { - immutableSize += Int64(fileSize) - } - } - } - if let logFilesPath = logFilesPath, let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logFilesPath), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { - for url in files { - if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { - immutableSize += Int64(fileSize) - } - } - } - - for additionalPath in additionalCachePaths { - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: additionalPath), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { - for url in enumerator { - if let url = url as? URL { - if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { - } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { - tempPaths.append(url.path) - - if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { - } else { - tempSize += Int64(fileSizeValue) - } - } - } - } - } - } - - var otherSize: Int64 = 0 - var otherPaths: [String] = [] - - for (id, name, size) in resourceList { - if size == 0 { - continue - } - if let id = id, processedResourceIds.contains(id) { - continue - } - otherSize += size - otherPaths.append(name) - } - - var cacheSize: Int64 = 0 - let basePath = account.postbox.mediaBox.basePath - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { - loop: for url in enumerator { - if let url = url as? URL { - if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { - otherPaths.append("cache/" + url.lastPathComponent) - cacheSize += Int64(value) - } - } - } - } - - func processRecursive(directoryPath: String, subdirectoryPath: String) { - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: directoryPath), includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { - loop: for url in enumerator { - if let url = url as? URL { - if let isDirectory = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectory { - processRecursive(directoryPath: url.path, subdirectoryPath: subdirectoryPath + "/\(url.lastPathComponent)") - } else if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { - otherPaths.append("\(subdirectoryPath)/" + url.lastPathComponent) - cacheSize += Int64(value) - } - } - } - } - } - - processRecursive(directoryPath: basePath + "/animation-cache", subdirectoryPath: "animation-cache") - - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/short-cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { - loop: for url in enumerator { - if let url = url as? URL { - if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { - otherPaths.append("short-cache/" + url.lastPathComponent) - cacheSize += Int64(value) - } - } - } - } - - return .result(CacheUsageStats( - media: media, - mediaResourceIds: mediaResourceIds, - peers: peers, - otherSize: otherSize, - otherPaths: otherPaths, - cacheSize: 0, - tempPaths: tempPaths, - tempSize: tempSize, - immutableSize: immutableSize - )) + return account.postbox.mediaBox.storageBox.all() + |> mapToSignal { entries -> Signal in + final class IncrementalState { + var startIndex: Int = 0 + + var media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]] = [:] + var mediaResourceIds: [MediaId: [MediaResourceId]] = [:] + var totalSize: Int64 = 0 + var mediaSize: Int64 = 0 + + var processedResourceIds = Set() + + var otherSize: Int64 = 0 + var otherPaths: [String] = [] + + var peers: [PeerId: Peer] = [:] + } + + let mediaBox = account.postbox.mediaBox + + let queue = Queue() + return Signal { subscriber in + var isCancelled: Bool = false + + let state = Atomic(value: IncrementalState()) + + var processNextBatchPtr: (() -> Void)? + let processNextBatch: () -> Void = { + if isCancelled { + return } + + let _ = (account.postbox.transaction { transaction -> Void in + state.with { state in + if state.startIndex >= entries.count { + return + } + + let batchCount = 5000 + let endIndex = min(state.startIndex + batchCount, entries.count) + for i in state.startIndex ..< endIndex { + let entry = entries[i] + + guard let resourceIdString = String(data: entry.id, encoding: .utf8) else { + continue + } + let resourceId = MediaResourceId(resourceIdString) + if state.processedResourceIds.contains(resourceId.stringRepresentation) { + continue + } + + let resourceSize = mediaBox.resourceUsage(id: resourceId) + if resourceSize != 0 { + state.totalSize += resourceSize + + for reference in entry.references { + if reference.peerId == 0 { + state.otherSize += resourceSize + + let storePaths = mediaBox.storePathsForId(resourceId) + state.otherPaths.append(storePaths.complete) + state.otherPaths.append(storePaths.partial) + + continue + } + if let message = transaction.getMessage(MessageId(peerId: PeerId(reference.peerId), namespace: MessageId.Namespace(reference.messageNamespace), id: reference.messageId)) { + for mediaItem in message.media { + guard let mediaId = mediaItem.id else { + continue + } + var category: PeerCacheUsageCategory? + if let _ = mediaItem as? TelegramMediaImage { + category = .image + } else if let mediaItem = mediaItem as? TelegramMediaFile { + if mediaItem.isMusic || mediaItem.isVoice { + category = .audio + } else if mediaItem.isVideo { + category = .video + } else { + category = .file + } + } + if let category = category { + state.mediaSize += resourceSize + state.processedResourceIds.insert(resourceId.stringRepresentation) + + state.media[PeerId(reference.peerId), default: [:]][category, default: [:]][mediaId, default: 0] += resourceSize + if let index = state.mediaResourceIds.index(forKey: mediaId) { + if !state.mediaResourceIds[index].value.contains(resourceId) { + state.mediaResourceIds[mediaId]?.append(resourceId) + } + } else { + state.mediaResourceIds[mediaId] = [resourceId] + } + } + } + } + } + } + } + state.startIndex = endIndex + } + }).start(completed: { + if isCancelled { + return + } + let isFinished = state.with { state -> Bool in + return state.startIndex >= entries.count + } + if !isFinished { + queue.async { + processNextBatchPtr?() + } + } else { + let _ = (account.postbox.transaction { transaction -> Void in + state.with { state in + for peerId in state.media.keys { + if let peer = transaction.getPeer(peerId) { + state.peers[peer.id] = peer + } + } + } + }).start(completed: { + queue.async { + let state = state.with { $0 } + var tempPaths: [String] = [] + var tempSize: Int64 = 0 + #if os(iOS) + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: NSTemporaryDirectory()), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { + for url in enumerator { + if let url = url as? URL { + if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { + tempPaths.append(url.path) + } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { + tempPaths.append(url.path) + + if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { + } else { + tempSize += Int64(fileSizeValue) + } + } + } + } + } + #endif + + var immutableSize: Int64 = 0 + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: account.basePath + "/postbox/db"), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { + for url in files { + if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { + immutableSize += Int64(fileSize) + } + } + } + if let logFilesPath = logFilesPath, let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logFilesPath), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { + for url in files { + if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { + immutableSize += Int64(fileSize) + } + } + } + + for additionalPath in additionalCachePaths { + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: additionalPath), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { + for url in enumerator { + if let url = url as? URL { + if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { + } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { + tempPaths.append(url.path) + + if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { + } else { + tempSize += Int64(fileSizeValue) + } + } + } + } + } + } + + var cacheSize: Int64 = 0 + let basePath = account.postbox.mediaBox.basePath + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { + loop: for url in enumerator { + if let url = url as? URL { + if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { + state.otherPaths.append("cache/" + url.lastPathComponent) + cacheSize += Int64(value) + } + } + } + } + + func processRecursive(directoryPath: String, subdirectoryPath: String) { + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: directoryPath), includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { + loop: for url in enumerator { + if let url = url as? URL { + if let isDirectory = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectory { + processRecursive(directoryPath: url.path, subdirectoryPath: subdirectoryPath + "/\(url.lastPathComponent)") + } else if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { + state.otherPaths.append("\(subdirectoryPath)/" + url.lastPathComponent) + cacheSize += Int64(value) + } + } + } + } + } + + processRecursive(directoryPath: basePath + "/animation-cache", subdirectoryPath: "animation-cache") + + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/short-cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { + loop: for url in enumerator { + if let url = url as? URL { + if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 { + state.otherPaths.append("short-cache/" + url.lastPathComponent) + cacheSize += Int64(value) + } + } + } + } + + subscriber.putNext(.result(CacheUsageStats( + media: state.media, + mediaResourceIds: state.mediaResourceIds, + peers: state.peers, + otherSize: state.otherSize, + otherPaths: state.otherPaths, + cacheSize: cacheSize, + tempPaths: tempPaths, + tempSize: tempSize, + immutableSize: immutableSize + ))) + subscriber.putCompletion() + } + }) + } + }) + } + processNextBatchPtr = { + processNextBatch() + } + + processNextBatch() + + return ActionDisposable { + isCancelled = true } } + |> runOn(queue) } - let initialState = CacheUsageStatsState() + /*let initialState = CacheUsageStatsState() if let peerId = peerId { initialState.lowerBound = MessageIndex.lowerBound(peerId: peerId) initialState.upperBound = MessageIndex.upperBound(peerId: peerId) @@ -485,7 +539,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a return .complete() } } - } + }*/ } func _internal_clearCachedMediaResources(account: Account, mediaResourceIds: Set) -> Signal { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift index dbf3f6febf..cb9f1bdc8d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift @@ -6,6 +6,24 @@ import TelegramApi public typealias EngineTempBox = TempBox public typealias EngineTempBoxFile = TempBoxFile +public extension MediaResourceUserContentType { + init(file: TelegramMediaFile) { + if file.isSticker || file.isAnimatedSticker { + self = .sticker + } else if file.isCustomEmoji { + self = .emoji + } else if file.isVideo { + if file.isAnimated { + self = .gif + } else { + self = .video + } + } else { + self = .other + } + } +} + func bufferedFetch(_ signal: Signal) -> Signal { return Signal { subscriber in final class State { @@ -294,6 +312,7 @@ public extension TelegramEngine { continueInBackground: false ), location: nil, + contentType: .image, isRandomAccessAllowed: true )) |> map { result -> EngineMediaResource.Fetch.Result in diff --git a/submodules/TelegramPresentationData/Sources/ChatControllerBackgroundNode.swift b/submodules/TelegramPresentationData/Sources/ChatControllerBackgroundNode.swift index f8fc943be9..a410693ee4 100644 --- a/submodules/TelegramPresentationData/Sources/ChatControllerBackgroundNode.swift +++ b/submodules/TelegramPresentationData/Sources/ChatControllerBackgroundNode.swift @@ -189,7 +189,7 @@ public func chatControllerBackgroundImageSignal(wallpaper: TelegramWallpaper, me } } else { return Signal { subscriber in - let fetch = fetchedMediaResource(mediaBox: accountMediaBox, reference: MediaResourceReference.wallpaper(wallpaper: WallpaperReference.slug(file.slug), resource: file.file.resource)).start() + let fetch = fetchedMediaResource(mediaBox: accountMediaBox, userLocation: .other, userContentType: .other, reference: MediaResourceReference.wallpaper(wallpaper: WallpaperReference.slug(file.slug), resource: file.file.resource)).start() var didOutputBlurred = false let data = accountMediaBox.cachedResourceRepresentation(file.file.resource, representation: representation, complete: true, fetch: true, attemptSynchronously: true).start(next: { data in if data.complete { @@ -227,7 +227,7 @@ public func chatControllerBackgroundImageSignal(wallpaper: TelegramWallpaper, me } } else { return Signal { subscriber in - let fetch = fetchedMediaResource(mediaBox: accountMediaBox, reference: MediaResourceReference.wallpaper(wallpaper: WallpaperReference.slug(file.slug), resource: file.file.resource)).start() + let fetch = fetchedMediaResource(mediaBox: accountMediaBox, userLocation: .other, userContentType: .other, reference: MediaResourceReference.wallpaper(wallpaper: WallpaperReference.slug(file.slug), resource: file.file.resource)).start() var didOutputBlurred = false let data = accountMediaBox.resourceData(file.file.resource).start(next: { data in if data.complete { diff --git a/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift b/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift index bf2fbcb135..64b86c15f3 100644 --- a/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift @@ -420,6 +420,7 @@ public final class EmojiStatusComponent: Component { } animationLayer = InlineStickerItemLayer( context: component.context, + userLocation: .other, attemptSynchronousLoad: false, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: emojiFile.fileId.id, file: emojiFile), file: emojiFile, diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift index d20bbd009d..05e2452a9c 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift @@ -39,7 +39,7 @@ private func randomGenericReactionEffect(context: AccountContext) -> Signal filter(\.complete) |> take(1)).start(next: { data in @@ -687,6 +687,7 @@ public final class EmojiStatusSelectionController: ViewController { for animationLayer in allLayers { let baseItemLayer = InlineStickerItemLayer( context: self.context, + userLocation: .other, attemptSynchronousLoad: false, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: itemFile.fileId.id, file: itemFile), file: item.itemFile, diff --git a/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift b/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift index f79dadb7a6..cf1c08aa50 100644 --- a/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift +++ b/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift @@ -107,6 +107,7 @@ public final class EmojiSuggestionsComponent: Component { public init( context: AccountContext, + userLocation: MediaResourceUserLocation, theme: PresentationTheme, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, @@ -283,6 +284,7 @@ public final class EmojiSuggestionsComponent: Component { } else { itemLayer = InlineStickerItemLayer( context: component.context, + userLocation: .other, attemptSynchronousLoad: synchronousLoad, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: item.fileId.id, file: item), file: item, diff --git a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift index 4a3215b924..dbfcd10f6c 100644 --- a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift +++ b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift @@ -96,7 +96,7 @@ public extension AnimationCacheAnimationType { } } -public func animationCacheFetchFile(context: AccountContext, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable { +public func animationCacheFetchFile(context: AccountContext, userLocation: MediaResourceUserLocation, userContentType: MediaResourceUserContentType, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable { return { options in let source = AnimatedStickerResourceSource(account: context.account, resource: resource.resource, fitzModifier: nil, isVideo: false) @@ -119,7 +119,7 @@ public func animationCacheFetchFile(context: AccountContext, resource: MediaReso } }) - let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: resource).start() + let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: userLocation, userContentType: userContentType, reference: resource).start() return ActionDisposable { dataDisposable.dispose() @@ -142,6 +142,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { } private let context: AccountContext + private let userLocation: MediaResourceUserLocation private let emoji: ChatTextInputTextCustomEmojiAttribute private let cache: AnimationCache private let renderer: MultiAnimationRenderer @@ -188,8 +189,9 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { } } - public init(context: AccountContext, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) { + public init(context: AccountContext, userLocation: MediaResourceUserLocation, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) { self.context = context + self.userLocation = userLocation self.emoji = emoji self.cache = cache self.renderer = renderer @@ -342,7 +344,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { let pointSize = self.pointSize let placeholderColor = self.placeholderColor let isThumbnailCancelled = Atomic(value: false) - self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true, customColor: isTemplate ? .white : nil), completion: { [weak self] result, isFinal in + self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true, customColor: isTemplate ? .white : nil), completion: { [weak self] result, isFinal in if !result { MultiAnimationRendererImpl.firstFrameQueue.async { let image = generateStickerPlaceholderImage(data: file.immediateThumbnailData, size: pointSize, scale: min(2.0, UIScreenScale), imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: placeholderColor) @@ -389,7 +391,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { if file.isAnimatedSticker || file.isVideoEmoji { let keyframeOnly = self.pixelSize.width >= 120.0 - self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil)) + self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, userLocation: self.userLocation, userContentType: .sticker, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil)) } else { self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: { options in let dataDisposable = context.account.postbox.mediaBox.resourceData(file.resource).start(next: { result in @@ -400,7 +402,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: isTemplate ? .white : nil) }) - let fetchDisposable = freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .customEmoji(media: file), resource: file.resource).start() + let fetchDisposable = freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: self.userLocation, fileReference: .customEmoji(media: file), resource: file.resource).start() return ActionDisposable { dataDisposable.dispose() @@ -459,8 +461,8 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { public final class EmojiTextAttachmentView: UIView { private let contentLayer: InlineStickerItemLayer - public init(context: AccountContext, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) { - self.contentLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: true, emoji: emoji, file: file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: pointSize) + public init(context: AccountContext, userLocation: MediaResourceUserLocation, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, placeholderColor: UIColor, pointSize: CGSize) { + self.contentLayer = InlineStickerItemLayer(context: context, userLocation: userLocation, attemptSynchronousLoad: true, emoji: emoji, file: file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: pointSize) super.init(frame: CGRect()) diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 6421a421b7..981ce53e50 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -2908,14 +2908,14 @@ public final class EmojiPagerContentComponent: Component { return } - strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0, customColor: animationData.isTemplate ? .white : nil)) + strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, userLocation: .other, userContentType: .sticker, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0, customColor: animationData.isTemplate ? .white : nil)) } if attemptSynchronousLoad { if !renderer.loadFirstFrameSynchronously(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize) { self.updateDisplayPlaceholder(displayPlaceholder: true) - self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in + self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, userLocation: .other, userContentType: .sticker, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in if !isFinal { if !success { Queue.mainQueue().async { @@ -2945,7 +2945,7 @@ public final class EmojiPagerContentComponent: Component { loadAnimation() } } else { - self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in + self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, userLocation: .other, userContentType: .sticker, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in if !isFinal { if !success { Queue.mainQueue().async { diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift index 9bf011d9eb..8f6525bd8c 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/GifPagerContentComponent.swift @@ -23,6 +23,7 @@ import ShimmerEffect private class GifVideoLayer: AVSampleBufferDisplayLayer { private let context: AccountContext + private let userLocation: MediaResourceUserLocation private let file: TelegramMediaFile? private var frameManager: SoftwareVideoLayerFrameManager? @@ -59,8 +60,9 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer { } } - init(context: AccountContext, file: TelegramMediaFile?, synchronousLoad: Bool) { + init(context: AccountContext, userLocation: MediaResourceUserLocation, file: TelegramMediaFile?, synchronousLoad: Bool) { self.context = context + self.userLocation = userLocation self.file = file super.init() @@ -69,7 +71,7 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer { if let file = self.file { if let dimensions = file.dimensions { - self.thumbnailDisposable = (mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .savedGif(media: file), synchronousLoad: synchronousLoad, nilForEmptyResult: true) + self.thumbnailDisposable = (mediaGridMessageVideo(postbox: context.account.postbox, userLocation: userLocation, videoReference: .savedGif(media: file), synchronousLoad: synchronousLoad, nilForEmptyResult: true) |> deliverOnMainQueue).start(next: { [weak self] transform in guard let strongSelf = self else { return @@ -111,7 +113,7 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer { guard let file = self.file else { return } - let frameManager = SoftwareVideoLayerFrameManager(account: self.context.account, fileReference: .savedGif(media: file), layerHolder: nil, layer: self) + let frameManager = SoftwareVideoLayerFrameManager(account: self.context.account, userLocation: self.userLocation, userContentType: .gif, fileReference: .savedGif(media: file), layerHolder: nil, layer: self) self.frameManager = frameManager frameManager.started = { [weak self] in guard let strongSelf = self else { @@ -352,7 +354,7 @@ public final class GifPagerContentComponent: Component { self.item = item self.onUpdateDisplayPlaceholder = onUpdateDisplayPlaceholder - super.init(context: context, file: item?.file.media, synchronousLoad: attemptSynchronousLoad) + super.init(context: context, userLocation: .other, file: item?.file.media, synchronousLoad: attemptSynchronousLoad) if item == nil { self.updateDisplayPlaceholder(displayPlaceholder: true, duration: 0.0) diff --git a/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift b/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift index 0a6b61facc..e7140a7d5f 100644 --- a/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift +++ b/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift @@ -246,7 +246,7 @@ public final class TextNodeWithEntities { itemLayer.dynamicColor = item.textColor } else { let pointSize = floor(itemSize * 1.3) - itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor) + itemLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor) self.inlineStickerItemLayers[id] = itemLayer self.textNode.layer.addSublayer(itemLayer) @@ -411,7 +411,7 @@ public class ImmediateTextNodeWithEntities: TextNode { itemLayer.dynamicColor = item.textColor } else { let pointSize = floor(itemSize * 1.3) - itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor) + itemLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor) self.inlineStickerItemLayers[id] = itemLayer self.layer.addSublayer(itemLayer) diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 2b503d6463..6a7327c266 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -1300,6 +1300,55 @@ private func extractAccountManagerState(records: AccountRecordsView take(1) + |> deliverOnMainQueue).start(next: { sharedApplicationContext in + let _ = (sharedApplicationContext.sharedContext.activeAccountContexts + |> take(1) + |> deliverOnMainQueue).start(next: { activeAccounts in + var signals: Signal = .complete() + + for (_, context, _) in activeAccounts.accounts { + signals = signals |> then(context.account.cleanupTasks()) + } + + disposable.set(signals.start(completed: { + task.setTaskCompleted(success: true) + })) + }) + }) + + task.expirationHandler = { + disposable.dispose() + task.setTaskCompleted(success: false) + } + } + + BGTaskScheduler.shared.getPendingTaskRequests(completionHandler: { tasks in + if tasks.contains(where: { $0.identifier == taskId }) { + Logger.shared.log("App \(self.episodeId)", "Already have a cleanup task pending") + return + } + let request = BGProcessingTaskRequest(identifier: taskId) + request.requiresExternalPower = true + request.requiresNetworkConnectivity = false + + do { + try BGTaskScheduler.shared.submit(request) + } catch let e { + Logger.shared.log("App \(self.episodeId)", "Error submitting background task request: \(e)") + } + }) + } + return true } diff --git a/submodules/TelegramUI/Sources/ChatAvatarNavigationNode.swift b/submodules/TelegramUI/Sources/ChatAvatarNavigationNode.swift index 39b4f42154..397c22fca5 100644 --- a/submodules/TelegramUI/Sources/ChatAvatarNavigationNode.swift +++ b/submodules/TelegramUI/Sources/ChatAvatarNavigationNode.swift @@ -127,7 +127,7 @@ final class ChatAvatarNavigationNode: ASDisplayNode { if let photo = maybePhoto, 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, "header"), 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, "header"), 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 diff --git a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift index 4706b3ea44..6a548d5bb2 100644 --- a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift @@ -139,6 +139,7 @@ final class ChatBotInfoItemNode: ListViewItemNode { let videoContent = NativeVideoContent( id: .message(0, MediaId(namespace: 0, id: Int64.random(in: 0.. mapToSignal { _ in @@ -16193,58 +16193,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.commitPurposefulAction() let _ = self.presentVoiceMessageDiscardAlert(action: { - if self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback { - if url.hasSuffix(".m3u8") { - let navigationController = self.navigationController as? NavigationController - - let webPage = TelegramMediaWebpage( - webpageId: MediaId(namespace: 0, id: 0), - content: .Loaded(TelegramMediaWebpageLoadedContent( - url: url, - displayUrl: url, - hash: 0, - type: "video", - websiteName: nil, - title: nil, - text: nil, - embedUrl: url, - embedType: "video", - embedSize: nil, - duration: nil, - author: nil, - image: nil, - file: nil, - attributes: [], - instantPage: nil - )) - ) - let entry = InstantPageGalleryEntry( - index: 0, - pageId: webPage.webpageId, - media: InstantPageMedia( - index: 0, - media: webPage, - url: nil, - caption: nil, - credit: nil - ), - caption: nil, - credit: nil, - location: nil - ) - - let gallery = InstantPageGalleryController(context: self.context, webPage: webPage, entries: [entry], centralIndex: 0, replaceRootController: { [weak navigationController] controller, ready in - if let navigationController = navigationController { - navigationController.replaceTopController(controller, animated: false, ready: ready) - } - }, baseNavigationController: navigationController) - self.present(gallery, in: .window(.root), with: InstantPageGalleryControllerPresentationArguments(transitionArguments: { entry -> GalleryTransitionArguments? in - return nil - })) - return; - } - } - openUserGeneratedUrl(context: self.context, peerId: self.peerView?.peerId, url: url, concealed: concealed, skipUrlAuth: skipUrlAuth, skipConcealedAlert: skipConcealedAlert, present: { [weak self] c in self?.present(c, in: .window(.root)) }, openResolved: { [weak self] resolved in diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index e44425b188..9ddd9af51f 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1182,7 +1182,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState actions.append(.action(ContextMenuActionItem(text: isVideo ? chatPresentationInterfaceState.strings.Gallery_SaveVideo : chatPresentationInterfaceState.strings.Gallery_SaveImage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in - let _ = (saveToCameraRoll(context: context, postbox: context.account.postbox, mediaReference: mediaReference) + let _ = (saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: mediaReference) |> deliverOnMainQueue).start(completed: { Queue.mainQueue().after(0.2) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputMetaSectionItemNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputMetaSectionItemNode.swift index 0c4ee80922..7f873b8918 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputMetaSectionItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputMetaSectionItemNode.swift @@ -250,7 +250,7 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode { } animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers - self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start()) + self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start()) } else { self.textNode.attributedText = NSAttributedString(string: emoji, font: Font.regular(43.0), textColor: .black) let textSize = self.textNode.updateLayout(CGSize(width: 100.0, height: 100.0)) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift index d55f0eeebb..9b7cfa31be 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift @@ -290,12 +290,12 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode { let dimensions = item.stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedSize = item.large ? CGSize(width: 384.0, height: 384.0) : CGSize(width: 160.0, height: 160.0) if item.stickerItem.file.isVideoSticker { - self.imageNode.setSignal(chatMessageSticker(account: item.account, file: item.stickerItem.file, small: false, synchronousLoad: synchronousLoads && isVisible)) + self.imageNode.setSignal(chatMessageSticker(account: item.account, userLocation: .other, file: item.stickerItem.file, small: false, synchronousLoad: synchronousLoads && isVisible)) } else { - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.account.postbox, file: item.stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(fittedSize))) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.account.postbox, userLocation: .other, file: item.stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(fittedSize))) } self.updateVisibility() - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(item.stickerItem.file), resource: item.stickerItem.file.resource).start()) + self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, userLocation: .other, fileReference: stickerPackFileReference(item.stickerItem.file), resource: item.stickerItem.file.resource).start()) } else { if let animationNode = self.animationNode { animationNode.visibility = false @@ -304,8 +304,8 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode { self.imageNode.isHidden = false self.didSetUpAnimationNode = false } - self.imageNode.setSignal(chatMessageSticker(account: item.account, file: item.stickerItem.file, small: !item.large, synchronousLoad: synchronousLoads && isVisible)) - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(item.stickerItem.file), resource: chatMessageStickerResource(file: item.stickerItem.file, small: !item.large)).start()) + self.imageNode.setSignal(chatMessageSticker(account: item.account, userLocation: .other, file: item.stickerItem.file, small: !item.large, synchronousLoad: synchronousLoads && isVisible)) + self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, userLocation: .other, fileReference: stickerPackFileReference(item.stickerItem.file), resource: chatMessageStickerResource(file: item.stickerItem.file, small: !item.large)).start()) } self.currentState = (item.account, item.stickerItem, dimensions.cgSize) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift index cd351e0c90..6e3f92712c 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift @@ -249,7 +249,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers } if let resourceReference = resourceReference { - self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start()) + self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference).start()) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift index 8bc3bc39af..3bfa270792 100644 --- a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift @@ -239,8 +239,8 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.insertSubnode(imageNode, at: 0) strongSelf.insertSubnode(strongSelf.mediaBackgroundNode, at: 0) } - strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, photoReference: .message(message: MessageReference(item.message), media: image), displayAtSize: nil, storeToDownloadsPeerType: nil).start()) - let updateImageSignal = chatMessagePhoto(postbox: item.context.account.postbox, photoReference: .message(message: MessageReference(item.message), media: image), synchronousLoad: synchronousLoads) + strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: image), displayAtSize: nil, storeToDownloadsPeerType: nil).start()) + let updateImageSignal = chatMessagePhoto(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: image), synchronousLoad: synchronousLoads) imageNode.setSignal(updateImageSignal, attemptSynchronously: synchronousLoads) @@ -259,7 +259,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { if let image = image, let video = image.videoRepresentations.last, let id = image.id?.id { let videoFileReference = FileMediaReference.message(message: MessageReference(item.message), media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: image.representations, videoThumbnails: [], immediateThumbnailData: image.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])])) - let videoContent = NativeVideoContent(id: .profileVideo(id, "action"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) + let videoContent = NativeVideoContent(id: .profileVideo(id, "action"), userLocation: .peer(item.message.id.peerId), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) if videoContent.id != strongSelf.videoContent?.id { let mediaManager = item.context.sharedContext.mediaManager let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .secondaryOverlay) diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 3350e302f1..ef9cfb805b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -560,13 +560,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if self.telegramFile?.id != telegramFile.id { self.telegramFile = telegramFile let dimensions = telegramFile.dimensions ?? PixelDimensions(width: 512, height: 512) - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: telegramFile, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)), thumbnail: false, synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), file: telegramFile, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)), thumbnail: false, synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad) self.updateVisibility() - self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .message(message: MessageReference(item.message), media: telegramFile)).start()) + self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, userLocation: .peer(item.message.id.peerId), fileReference: .message(message: MessageReference(item.message), media: telegramFile)).start()) if telegramFile.isPremiumSticker { if let effect = telegramFile.videoThumbnails.first { - self.disposables.add(freeMediaFileResourceInteractiveFetched(account: item.context.account, fileReference: .message(message: MessageReference(item.message), media: telegramFile), resource: effect.resource) .start()) + self.disposables.add(freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .peer(item.message.id.peerId), fileReference: .message(message: MessageReference(item.message), media: telegramFile), resource: effect.resource) .start()) } } } @@ -628,8 +628,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let fillSize = emojiFile.isCustomEmoji ? CGSize(width: 512.0, height: 512.0) : CGSize(width: 384.0, height: 384.0) - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: emojiFile, small: false, size: dimensions.cgSize.aspectFilled(fillSize), fitzModifier: fitzModifier, thumbnail: false, synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad) - self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .standalone(media: emojiFile)).start()) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), file: emojiFile, small: false, size: dimensions.cgSize.aspectFilled(fillSize), fitzModifier: fitzModifier, thumbnail: false, synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad) + self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, userLocation: .peer(item.message.id.peerId), fileReference: .standalone(media: emojiFile)).start()) } let textEmoji = item.message.text.strippedEmoji @@ -653,7 +653,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let animationItems = animationItems { for (_, animationItem) in animationItems { - self.disposables.add(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .standalone(media: animationItem.file)).start()) + self.disposables.add(freeMediaFileInteractiveFetched(account: item.context.account, userLocation: .peer(item.message.id.peerId), fileReference: .standalone(media: animationItem.file)).start()) } } } @@ -2274,7 +2274,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if emoji.strippedEmoji == textEmoji.strippedEmoji { hasSound = true let mediaManager = item.context.sharedContext.mediaManager - let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true) + let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), userContentType: .other, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true) mediaPlayer.togglePlayPause() mediaPlayer.actionAtEnd = .action({ [weak self] in self?.mediaPlayer = nil diff --git a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift index f3fb5f65a8..bc7f1765b2 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift @@ -618,7 +618,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { inlineImageDimensions = dimensions.cgSize if image != currentImage { - updateInlineImageSignal = chatWebpageSnippetPhoto(account: context.account, photoReference: .message(message: MessageReference(message), media: image)) + updateInlineImageSignal = chatWebpageSnippetPhoto(account: context.account, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image)) } } } else if let image = media as? TelegramMediaWebFile { diff --git a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift index 17c792ff9c..3a406ea222 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift @@ -535,7 +535,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode { if let photo = maybePhoto, let video = photo.videoRepresentations.last, let peerReference = PeerReference(peer) { 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, "\(Int32.random(in: 0 ..< Int32.max))"), 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, "\(Int32.random(in: 0 ..< Int32.max))"), 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 diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 55078a1eb3..336ba4f749 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -528,7 +528,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { if mediaUpdated { if largestImageRepresentation(arguments.file.previewRepresentations) != nil || arguments.file.immediateThumbnailData != nil { - updateImageSignal = chatMessageImageFile(account: arguments.context.account, fileReference: .message(message: MessageReference(arguments.message), media: arguments.file), thumbnail: true) + updateImageSignal = chatMessageImageFile(account: arguments.context.account, userLocation: .peer(arguments.message.id.peerId), fileReference: .message(message: MessageReference(arguments.message), media: arguments.file), thumbnail: true) } updatedFetchControls = FetchControls(fetch: { [weak self] userInitiated in diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index 16ab0f01fc..b6d75323bc 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -612,7 +612,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { if let updatedFile = updatedFile, updatedMedia { if let resource = updatedFile.previewRepresentations.first?.resource { - strongSelf.fetchedThumbnailDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, reference: FileMediaReference.message(message: MessageReference(item.message), media: updatedFile).resourceReference(resource)).start()) + strongSelf.fetchedThumbnailDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .peer(item.message.id.peerId), userContentType: .video, reference: FileMediaReference.message(message: MessageReference(item.message), media: updatedFile).resourceReference(resource)).start()) } else { strongSelf.fetchedThumbnailDisposable.set(nil) } @@ -688,7 +688,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { } } } - }), content: NativeVideoContent(id: .message(item.message.stableId, telegramFile.fileId), fileReference: .message(message: MessageReference(item.message), media: telegramFile), streamVideo: streamVideo ? .conservative : .none, enableSound: false, fetchAutomatically: false, captureProtected: item.message.isCopyProtected()), priority: .embedded, autoplay: true) + }), content: NativeVideoContent(id: .message(item.message.stableId, telegramFile.fileId), userLocation: .peer(item.message.id.peerId), fileReference: .message(message: MessageReference(item.message), media: telegramFile), streamVideo: streamVideo ? .conservative : .none, enableSound: false, fetchAutomatically: false, captureProtected: item.message.isCopyProtected()), priority: .embedded, autoplay: true) if let previousVideoNode = previousVideoNode { videoNode.bounds = previousVideoNode.bounds videoNode.position = previousVideoNode.position @@ -699,7 +699,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { videoNode.canAttachContent = strongSelf.shouldAcquireVideoContext if isSecretMedia { - let updatedSecretPlaceholderSignal = chatSecretMessageVideo(account: item.context.account, videoReference: .message(message: MessageReference(item.message), media: telegramFile)) + let updatedSecretPlaceholderSignal = chatSecretMessageVideo(account: item.context.account, userLocation: .peer(item.message.id.peerId), videoReference: .message(message: MessageReference(item.message), media: telegramFile)) strongSelf.secretVideoPlaceholder.setSignal(updatedSecretPlaceholderSignal) if strongSelf.secretVideoPlaceholder.supernode == nil { strongSelf.insertSubnode(strongSelf.secretVideoPlaceholderBackground, belowSubnode: videoNode) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index 80b73fc822..6325310b78 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -972,14 +972,14 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio } if isSecretMedia { updateImageSignal = { synchronousLoad, _ in - return chatSecretPhoto(account: context.account, photoReference: .message(message: MessageReference(message), media: image)) + return chatSecretPhoto(account: context.account, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image)) } } else { updateImageSignal = { synchronousLoad, highQuality in - return chatMessagePhoto(postbox: context.account.postbox, photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: synchronousLoad, highQuality: highQuality) + return chatMessagePhoto(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: synchronousLoad, highQuality: highQuality) } updateBlurredImageSignal = { synchronousLoad, _ in - return chatSecretPhoto(account: context.account, photoReference: .message(message: MessageReference(message), media: image)) + return chatSecretPhoto(account: context.account, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image)) } } @@ -1008,7 +1008,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio updatedFetchControls = FetchControls(fetch: { _ in if let strongSelf = self { - strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start()) + strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, userLocation: .peer(message.id.peerId), image: image).start()) } }, cancel: { chatMessageWebFileCancelInteractiveFetch(account: context.account, image: image) @@ -1016,22 +1016,22 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio } else if let file = media as? TelegramMediaFile { if isSecretMedia { updateImageSignal = { synchronousLoad, _ in - return chatSecretMessageVideo(account: context.account, videoReference: .message(message: MessageReference(message), media: file)) + return chatSecretMessageVideo(account: context.account, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file)) } } else { if file.isAnimatedSticker { let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) updateImageSignal = { synchronousLoad, _ in - return chatMessageAnimatedSticker(postbox: context.account.postbox, file: file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 400.0, height: 400.0))) + return chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), file: file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 400.0, height: 400.0))) } } else if file.isSticker || file.isVideoSticker { updateImageSignal = { synchronousLoad, _ in - return chatMessageSticker(account: context.account, file: file, small: false) + return chatMessageSticker(account: context.account, userLocation: .peer(message.id.peerId), file: file, small: false) } } else { onlyFullSizeVideoThumbnail = isSendingUpdated updateImageSignal = { synchronousLoad, _ in - return mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile, autoFetchFullSizeThumbnail: true) + return mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile, autoFetchFullSizeThumbnail: true) } } } @@ -1082,7 +1082,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio updatedFetchControls = FetchControls(fetch: { manual in if let strongSelf = self { if file.isAnimated { - strongSelf.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start()) + strongSelf.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(message.id.peerId), userContentType: MediaResourceUserContentType(file: file), reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start()) } else { strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: manual).start()) } @@ -1266,7 +1266,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio let streamVideo = isMediaStreamable(message: message, media: updatedVideoFile) let loopVideo = updatedVideoFile.isAnimated - let videoContent = NativeVideoContent(id: .message(message.stableId, updatedVideoFile.fileId), fileReference: .message(message: MessageReference(message), media: updatedVideoFile), streamVideo: streamVideo ? .conservative : .none, loopVideo: loopVideo, enableSound: false, fetchAutomatically: false, onlyFullSizeThumbnail: (onlyFullSizeVideoThumbnail ?? false), continuePlayingWithoutSoundOnLostAudioSession: isInlinePlayableVideo, placeholderColor: emptyColor, captureProtected: message.isCopyProtected() || isExtendedMedia) + let videoContent = NativeVideoContent(id: .message(message.stableId, updatedVideoFile.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: updatedVideoFile), streamVideo: streamVideo ? .conservative : .none, loopVideo: loopVideo, enableSound: false, fetchAutomatically: false, onlyFullSizeThumbnail: (onlyFullSizeVideoThumbnail ?? false), continuePlayingWithoutSoundOnLostAudioSession: isInlinePlayableVideo, placeholderColor: emptyColor, captureProtected: message.isCopyProtected() || isExtendedMedia) let videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded) videoNode.isUserInteractionEnabled = false videoNode.ownsContentNodeUpdated = { [weak self] owns in @@ -1421,7 +1421,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio if let _ = media as? TelegramMediaImage { updatedFetchControls.fetch(false) } else if let image = media as? TelegramMediaWebFile { - strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start()) + strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, userLocation: .peer(message.id.peerId), image: image).start()) } else if let file = media as? TelegramMediaFile { let fetchSignal = messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: false) let visibilityAwareFetchSignal = strongSelf.visibilityPromise.get() @@ -1439,7 +1439,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio } } else if case .prefetch = automaticDownload, message.id.namespace != Namespaces.Message.SecretIncoming /*&& message.id.namespace != Namespaces.Message.Local*/ { if let file = media as? TelegramMediaFile { - let fetchSignal = preloadVideoResource(postbox: context.account.postbox, resourceReference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), duration: 4.0) + let fetchSignal = preloadVideoResource(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), userContentType: MediaResourceUserContentType(file: file), resourceReference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), duration: 4.0) let visibilityAwareFetchSignal = strongSelf.visibilityPromise.get() |> mapToSignal { visibility -> Signal in if visibility { diff --git a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift index 6a9bff67e6..d28819382a 100644 --- a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift @@ -350,12 +350,12 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? if let firstMessage = item.messages.first, let updatedMedia = updatedMedia, imageDimensions != nil { if let image = updatedMedia as? TelegramMediaImage { - updateImageSignal = mediaGridMessagePhoto(account: item.context.account, photoReference: .message(message: MessageReference(firstMessage), media: image)) + updateImageSignal = mediaGridMessagePhoto(account: item.context.account, userLocation: .peer(firstMessage.id.peerId), photoReference: .message(message: MessageReference(firstMessage), media: image)) } else if let file = updatedMedia as? TelegramMediaFile { if file.isSticker { - updateImageSignal = chatMessageSticker(account: item.context.account, file: file, small: true, fetched: true) + updateImageSignal = chatMessageSticker(account: item.context.account, userLocation: .peer(firstMessage.id.peerId), file: file, small: true, fetched: true) } else if file.isVideo { - updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, videoReference: .message(message: MessageReference(firstMessage), media: file), autoFetchFullSizeThumbnail: true) + updateImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, userLocation: .peer(firstMessage.id.peerId), videoReference: .message(message: MessageReference(firstMessage), media: file), autoFetchFullSizeThumbnail: true) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift index 2f9d92be17..146cf40f3f 100644 --- a/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift @@ -197,10 +197,10 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode if let photo = photo { if mediaUpdated { - strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, photoReference: .message(message: MessageReference(item.message), media: photo), displayAtSize: nil, storeToDownloadsPeerType: nil).start()) + strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: photo), displayAtSize: nil, storeToDownloadsPeerType: nil).start()) } - let updateImageSignal = chatMessagePhoto(postbox: item.context.account.postbox, photoReference: .message(message: MessageReference(item.message), media: photo), synchronousLoad: synchronousLoads) + let updateImageSignal = chatMessagePhoto(postbox: item.context.account.postbox, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: photo), synchronousLoad: synchronousLoads) strongSelf.imageNode.setSignal(updateImageSignal, attemptSynchronously: synchronousLoads) let arguments = TransformImageArguments(corners: ImageCorners(radius: imageSize.width / 2.0), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()) diff --git a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift index fa7c78f751..40931d48cb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift @@ -253,12 +253,12 @@ class ChatMessageReplyInfoNode: ASDisplayNode { var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? if let updatedMediaReference = updatedMediaReference, mediaUpdated && imageDimensions != nil { if let imageReference = updatedMediaReference.concrete(TelegramMediaImage.self) { - updateImageSignal = chatMessagePhotoThumbnail(account: arguments.context.account, photoReference: imageReference) + updateImageSignal = chatMessagePhotoThumbnail(account: arguments.context.account, userLocation: .peer(arguments.message.id.peerId), photoReference: imageReference) } else if let fileReference = updatedMediaReference.concrete(TelegramMediaFile.self) { if fileReference.media.isVideo { - updateImageSignal = chatMessageVideoThumbnail(account: arguments.context.account, fileReference: fileReference) + updateImageSignal = chatMessageVideoThumbnail(account: arguments.context.account, userLocation: .peer(arguments.message.id.peerId), fileReference: fileReference) } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { - updateImageSignal = chatWebpageSnippetFile(account: arguments.context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation) + updateImageSignal = chatWebpageSnippetFile(account: arguments.context.account, userLocation: .peer(arguments.message.id.peerId), mediaReference: fileReference.abstract, representation: iconImageRepresentation) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index da5210afb2..ab75b2edfa 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -256,10 +256,10 @@ class ChatMessageStickerItemNode: ChatMessageItemView { for media in item.message.media { if let telegramFile = media as? TelegramMediaFile { if self.telegramFile != telegramFile { - let signal = chatMessageSticker(account: item.context.account, file: telegramFile, small: false, onlyFullSize: self.telegramFile != nil, synchronousLoad: synchronousLoad) + let signal = chatMessageSticker(account: item.context.account, userLocation: .peer(item.message.id.peerId), file: telegramFile, small: false, onlyFullSize: self.telegramFile != nil, synchronousLoad: synchronousLoad) self.telegramFile = telegramFile self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoad) - self.fetchDisposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .message(message: MessageReference(item.message), media: telegramFile)).start()) + self.fetchDisposable.set(freeMediaFileInteractiveFetched(account: item.context.account, userLocation: .peer(item.message.id.peerId), fileReference: .message(message: MessageReference(item.message), media: telegramFile)).start()) } break diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index 691833356b..fda53c1487 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -627,16 +627,16 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { if mediaUpdated { if let updatedMediaReference = updatedMediaReference, imageDimensions != nil { if let imageReference = updatedMediaReference.concrete(TelegramMediaImage.self) { - updateImageSignal = chatMessagePhotoThumbnail(account: context.account, photoReference: imageReference) + updateImageSignal = chatMessagePhotoThumbnail(account: context.account, userLocation: .peer(message.id.peerId), photoReference: imageReference) } else if let fileReference = updatedMediaReference.concrete(TelegramMediaFile.self) { if fileReference.media.isAnimatedSticker { let dimensions = fileReference.media.dimensions ?? PixelDimensions(width: 512, height: 512) - updateImageSignal = chatMessageAnimatedSticker(postbox: context.account.postbox, file: fileReference.media, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))) - updatedFetchMediaSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)) + updateImageSignal = chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), file: fileReference.media, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))) + updatedFetchMediaSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(message.id.peerId), userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(fileReference.media.resource)) } else if fileReference.media.isVideo || fileReference.media.isAnimated { - updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) + updateImageSignal = chatMessageVideoThumbnail(account: context.account, userLocation: .peer(message.id.peerId), fileReference: fileReference) } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { - updateImageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation) + updateImageSignal = chatWebpageSnippetFile(account: context.account, userLocation: .peer(message.id.peerId), mediaReference: fileReference.abstract, representation: iconImageRepresentation) } } } else { diff --git a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift index 821cead160..0279c92fd7 100644 --- a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift @@ -513,7 +513,7 @@ private final class ThemeSettingsThemeItemIconNode : 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) @@ -1122,7 +1122,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in let accountResource = account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPreparedPatternWallpaperRepresentation(), complete: false, fetch: true) - let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .media(media: .standalone(media: file.file), resource: file.file.resource)) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: file.file), reference: .media(media: .standalone(media: file.file), resource: file.file.resource)) let fetchedFullSizeDisposable = fetchedFullSize.start() let fullSizeDisposable = accountResource.start(next: { next in subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete)) @@ -2150,7 +2150,7 @@ private class MessageContentNode: ASDisplayNode, ContentNode { guard let image = image, let videoFrame = videoFrame else { return } - renderVideo(context: context, backgroundImage: image, media: media, videoFrame: videoFrame, completion: { url in + renderVideo(context: context, backgroundImage: image, userLocation: .peer(message.id.peerId), media: media, videoFrame: videoFrame, completion: { url in if let url = url { completion(url) } @@ -2238,7 +2238,7 @@ private class MessageContentNode: ASDisplayNode, ContentNode { mediaFrame = CGRect(origin: CGPoint(x: 3.0, y: 63.0), size: mediaSize) if !wasInitialized { - self.imageNode.setSignal(chatMessagePhoto(postbox: self.context.account.postbox, photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: true, highQuality: true)) + self.imageNode.setSignal(chatMessagePhoto(postbox: self.context.account.postbox, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: true, highQuality: true)) let imageLayout = self.imageNode.asyncLayout() let arguments = TransformImageArguments(corners: ImageCorners(radius: 0.0), imageSize: mediaSize, boundingSize: mediaSize, intrinsicInsets: UIEdgeInsets(), resizeMode: .blurBackground, emptyColor: .black, custom: nil) @@ -2261,7 +2261,7 @@ private class MessageContentNode: ASDisplayNode, ContentNode { videoSnapshotView.frame = mediaFrame } } else { - let videoContent = NativeVideoContent(id: .message(message.stableId, video.fileId), fileReference: .message(message: MessageReference(message), media: video), streamVideo: .conservative, loopVideo: true, enableSound: false, fetchAutomatically: false, onlyFullSizeThumbnail: self.isStatic, continuePlayingWithoutSoundOnLostAudioSession: true, placeholderColor: .clear, captureProtected: false) + let videoContent = NativeVideoContent(id: .message(message.stableId, video.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: video), streamVideo: .conservative, loopVideo: true, enableSound: false, fetchAutomatically: false, onlyFullSizeThumbnail: self.isStatic, continuePlayingWithoutSoundOnLostAudioSession: true, placeholderColor: .clear, captureProtected: false) let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: self.context.sharedContext.mediaManager.audioSession, manager: self.context.sharedContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .overlay, autoplay: !self.isStatic) self.videoStatusDisposable.set((videoNode.status @@ -2394,8 +2394,8 @@ private enum RenderVideoResult { case error } -private func renderVideo(context: AccountContext, backgroundImage: UIImage, media: TelegramMediaFile, videoFrame: CGRect, completion: @escaping (URL?) -> Void) { - let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: AnyMediaReference.standalone(media: media)) +private func renderVideo(context: AccountContext, backgroundImage: UIImage, userLocation: MediaResourceUserLocation, media: TelegramMediaFile, videoFrame: CGRect, completion: @escaping (URL?) -> Void) { + let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: userLocation, mediaReference: AnyMediaReference.standalone(media: media)) |> deliverOnMainQueue).start(next: { value, isImage in guard case let .data(data) = value, data.complete else { return diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 04261503ed..1269bd3924 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -1013,7 +1013,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }), in: .current)*/ }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) case let .instantView(webpage, anchor): - strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)) + strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: .peer(strongSelf.peer.id), peerType: .channel), anchor: anchor)) case let .join(link): strongSelf.presentController(JoinLinkPreviewController(context: strongSelf.context, link: link, navigateToPeer: { peer, peekData in if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift index 42a2812bdf..35e4195931 100644 --- a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift @@ -157,8 +157,8 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode { } if let context = self.context { let mediaManager = context.sharedContext.mediaManager - let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: context.account.postbox, resourceReference: .standalone(resource: recordedMediaPreview.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true) - mediaPlayer.actionAtEnd = .action{ [weak mediaPlayer] in + let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: context.account.postbox, userLocation: .other, userContentType: .audio, resourceReference: .standalone(resource: recordedMediaPreview.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true) + mediaPlayer.actionAtEnd = .action { [weak mediaPlayer] in mediaPlayer?.seek(timestamp: 0.0) } self.mediaPlayer = mediaPlayer diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 874a7f1293..befdfa76f9 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1012,7 +1012,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } let pointSize = floor(24.0 * 1.3) - return EmojiTextAttachmentView(context: context, emoji: emoji, file: emoji.file, cache: presentationContext.animationCache, renderer: presentationContext.animationRenderer, placeholderColor: presentationInterfaceState.theme.chat.inputPanel.inputTextColor.withAlphaComponent(0.12), pointSize: CGSize(width: pointSize, height: pointSize)) + return EmojiTextAttachmentView(context: context, userLocation: .other, emoji: emoji, file: emoji.file, cache: presentationContext.animationCache, renderer: presentationContext.animationRenderer, placeholderColor: presentationInterfaceState.theme.chat.inputPanel.inputTextColor.withAlphaComponent(0.12), pointSize: CGSize(width: pointSize, height: pointSize)) } } } @@ -2585,6 +2585,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { transition: .immediate, component: AnyComponent(EmojiSuggestionsComponent( context: context, + userLocation: .other, theme: theme, animationCache: presentationContext.animationCache, animationRenderer: presentationContext.animationRenderer, diff --git a/submodules/TelegramUI/Sources/ChatThemeScreen.swift b/submodules/TelegramUI/Sources/ChatThemeScreen.swift index 883a7d5811..2575e6baae 100644 --- a/submodules/TelegramUI/Sources/ChatThemeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatThemeScreen.swift @@ -493,7 +493,7 @@ private final class ThemeSettingsThemeItemIconNode : 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) @@ -901,7 +901,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in let accountResource = account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPreparedPatternWallpaperRepresentation(), complete: false, fetch: true) - let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .media(media: .standalone(media: file.file), resource: file.file.resource)) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: file.file), reference: .media(media: .standalone(media: file.file), resource: file.file.resource)) let fetchedFullSizeDisposable = fetchedFullSize.start() let fullSizeDisposable = accountResource.start(next: { next in subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete)) diff --git a/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift index 9c53911751..1f0d8fdcc7 100644 --- a/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift @@ -237,13 +237,13 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { if mediaUpdated { if let updatedMediaReference = updatedMediaReference, imageDimensions != nil { if let imageReference = updatedMediaReference.concrete(TelegramMediaImage.self) { - updateImageSignal = chatMessagePhotoThumbnail(account: self.context.account, photoReference: imageReference) + updateImageSignal = chatMessagePhotoThumbnail(account: self.context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, photoReference: imageReference) isPhoto = true } else if let fileReference = updatedMediaReference.concrete(TelegramMediaFile.self) { if fileReference.media.isVideo { - updateImageSignal = chatMessageVideoThumbnail(account: self.context.account, fileReference: fileReference) + updateImageSignal = chatMessageVideoThumbnail(account: self.context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, fileReference: fileReference) } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { - updateImageSignal = chatWebpageSnippetFile(account: self.context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation) + updateImageSignal = chatWebpageSnippetFile(account: self.context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, mediaReference: fileReference.abstract, representation: iconImageRepresentation) } } } else { diff --git a/submodules/TelegramUI/Sources/EmojisChatInputPanelItem.swift b/submodules/TelegramUI/Sources/EmojisChatInputPanelItem.swift index 6420e83f3b..842d3266d1 100644 --- a/submodules/TelegramUI/Sources/EmojisChatInputPanelItem.swift +++ b/submodules/TelegramUI/Sources/EmojisChatInputPanelItem.swift @@ -135,6 +135,7 @@ final class EmojisChatInputPanelItemNode: ListViewItemNode { } else { emojiView = EmojiTextAttachmentView( context: item.context, + userLocation: .other, emoji: ChatTextInputTextCustomEmojiAttribute( interactivelySelectedFromPackId: nil, fileId: file.fileId.id, diff --git a/submodules/TelegramUI/Sources/GridMessageItem.swift b/submodules/TelegramUI/Sources/GridMessageItem.swift index b5aa53490b..5e56689691 100644 --- a/submodules/TelegramUI/Sources/GridMessageItem.swift +++ b/submodules/TelegramUI/Sources/GridMessageItem.swift @@ -219,7 +219,7 @@ final class GridMessageItemNode: GridItemNode { 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(item.message), media: image), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true) + self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: image), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true) self.fetchStatusDisposable.set(nil) self.statusNode.transitionToState(.none, completion: { [weak self] in @@ -229,7 +229,7 @@ final class GridMessageItemNode: GridItemNode { 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(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) + self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(item.message.id.peerId), videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) self.mediaBadgeNode.isHidden = false diff --git a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputPanelItem.swift b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputPanelItem.swift index e6379e9325..edcc29dd7b 100644 --- a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputPanelItem.swift +++ b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputPanelItem.swift @@ -350,11 +350,11 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode if updatedImageResource { if let imageResource = imageResource { if let stickerFile = stickerFile { - updateImageSignal = chatMessageSticker(account: item.account, file: stickerFile, small: false, fetched: true) + updateImageSignal = chatMessageSticker(account: item.account, userLocation: .other, file: stickerFile, small: false, fetched: true) } else { let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(CGSize(width: fittedImageDimensions.width * 2.0, height: fittedImageDimensions.height * 2.0)), resource: imageResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []) - updateImageSignal = chatMessagePhoto(postbox: item.account.postbox, photoReference: .standalone(media: tmpImage), synchronousLoad: true) + updateImageSignal = chatMessagePhoto(postbox: item.account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage), synchronousLoad: true) } } else { updateImageSignal = .complete() @@ -398,7 +398,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode layerHolder.layer.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) strongSelf.layer.addSublayer(layerHolder.layer) - let manager = SoftwareVideoLayerFrameManager(account: item.account, fileReference: .standalone(media: videoFile), layerHolder: layerHolder) + let manager = SoftwareVideoLayerFrameManager(account: item.account, userLocation: .other, userContentType: .gif, fileReference: .standalone(media: videoFile), layerHolder: layerHolder) strongSelf.videoLayer = (thumbnailLayer, manager, layerHolder) thumbnailLayer.ready = { [weak thumbnailLayer, weak manager] in if let strongSelf = self, let thumbnailLayer = thumbnailLayer, let manager = manager { @@ -436,7 +436,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode } let dimensions = animatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) - strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start()) + strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, userLocation: .other, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start()) animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: animatedStickerFile.resource, isVideo: animatedStickerFile.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached) } } diff --git a/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift b/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift index a19783d16d..82a28606dd 100755 --- a/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift +++ b/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift @@ -161,9 +161,9 @@ final class HorizontalStickerGridItemNode: GridItemNode { let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) if item.file.isVideoSticker { - self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, file: item.file, small: true, synchronousLoad: false)) + self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, synchronousLoad: false)) } else { - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false)) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false)) } animationNode.started = { [weak self] in guard let strongSelf = self else { @@ -183,17 +183,17 @@ final class HorizontalStickerGridItemNode: GridItemNode { } animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached) - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start()) + self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start()) } else { self.imageNode.alpha = 1.0 - self.imageNode.setSignal(chatMessageSticker(account: account, file: item.file, small: true)) + self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: true)) if let currentAnimationNode = self.animationNode { self.animationNode = nil currentAnimationNode.removeFromSupernode() } - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start()) + self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start()) } if item.file.isPremiumSticker { diff --git a/submodules/TelegramUI/Sources/InChatPrefetchManager.swift b/submodules/TelegramUI/Sources/InChatPrefetchManager.swift index 8f06916e22..b75a1ce57c 100644 --- a/submodules/TelegramUI/Sources/InChatPrefetchManager.swift +++ b/submodules/TelegramUI/Sources/InChatPrefetchManager.swift @@ -114,7 +114,7 @@ final class InChatPrefetchManager { } } else if case .prefetch = automaticDownload, message.id.peerId.namespace != Namespaces.Peer.SecretChat { if let file = media as? TelegramMediaFile, let _ = file.size { - context.fetchDisposable.set(preloadVideoResource(postbox: self.context.account.postbox, resourceReference: FileMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), duration: 4.0).start()) + context.fetchDisposable.set(preloadVideoResource(postbox: self.context.account.postbox, userLocation: .peer(message.id.peerId), userContentType: MediaResourceUserContentType(file: file), resourceReference: FileMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), duration: 4.0).start()) } } } diff --git a/submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift b/submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift index b76a421208..cc385e6282 100644 --- a/submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift +++ b/submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift @@ -92,8 +92,8 @@ private final class LargeEmojiActionSheetItemNode: ActionSheetItemNode { self.accessibilityArea.accessibilityTraits = .staticText let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, file: file, small: false, size: dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: fitzModifier, thumbnail: false, synchronousLoad: true), attemptSynchronously: true) - self.disposable.set(freeMediaFileInteractiveFetched(account: context.account, fileReference: .standalone(media: file)).start()) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: file, small: false, size: dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: fitzModifier, thumbnail: false, synchronousLoad: true), attemptSynchronously: true) + self.disposable.set(freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: file)).start()) self.setupTimestamp = CACurrentMediaTime() diff --git a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift index 44b58d9a48..5589c14e15 100644 --- a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift +++ b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift @@ -37,7 +37,7 @@ private func animationItem(account: Account, emojis: Signal<[TelegramMediaFile], let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedSize = dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)) - let fetched = freeMediaFileInteractiveFetched(account: account, fileReference: .standalone(media: file)) + let fetched = freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: file)) let animationItem = Signal { subscriber in let fetchedDisposable = fetched.start() let resourceDisposable = (chatMessageAnimationData(mediaBox: account.postbox.mediaBox, resource: file.resource, fitzModifier: nil, width: Int(fittedSize.width), height: Int(fittedSize.height), synchronousLoad: false) diff --git a/submodules/TelegramUI/Sources/MediaInputPaneTrendingItem.swift b/submodules/TelegramUI/Sources/MediaInputPaneTrendingItem.swift index e16263b237..871c3aee3c 100644 --- a/submodules/TelegramUI/Sources/MediaInputPaneTrendingItem.swift +++ b/submodules/TelegramUI/Sources/MediaInputPaneTrendingItem.swift @@ -134,23 +134,23 @@ final class TrendingTopItemNode: ASDisplayNode { let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) if item.file.isVideoSticker { - self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, file: item.file, small: false, synchronousLoad: synchronousLoads)) + self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: false, synchronousLoad: synchronousLoads)) } else { - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: item.file, small: false, size: fittedDimensions, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: false, size: fittedDimensions, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads) } animationNode.started = { [weak self] in self?.imageNode.alpha = 0.0 } animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached) - self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start()) + self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start()) } else { - self.imageNode.setSignal(chatMessageSticker(account: account, file: item.file, small: true, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads) + self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: true, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads) if let currentAnimationNode = self.animationNode { self.animationNode = nil currentAnimationNode.removeFromSupernode() } - self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start()) + self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start()) } } diff --git a/submodules/TelegramUI/Sources/MultiplexedVideoNode.swift b/submodules/TelegramUI/Sources/MultiplexedVideoNode.swift index 80ba7707d0..d578efe6e7 100644 --- a/submodules/TelegramUI/Sources/MultiplexedVideoNode.swift +++ b/submodules/TelegramUI/Sources/MultiplexedVideoNode.swift @@ -463,7 +463,7 @@ final class MultiplexedVideoNode: ASDisplayNode, UIScrollViewDelegate { layerHolder.layer.videoGravity = AVLayerVideoGravity.resizeAspectFill layerHolder.layer.frame = item.frame self.scrollNode.layer.addSublayer(layerHolder.layer) - let manager = SoftwareVideoLayerFrameManager(account: self.account, fileReference: item.file.file, layerHolder: layerHolder) + let manager = SoftwareVideoLayerFrameManager(account: self.account, userLocation: .other, userContentType: .gif, fileReference: item.file.file, layerHolder: layerHolder) self.visibleLayers[item.id] = (manager, layerHolder) self.visibleThumbnailLayers[item.id]?.ready = { [weak self] in if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/NotificationContentContext.swift b/submodules/TelegramUI/Sources/NotificationContentContext.swift index 035a2cf1cf..a9a050ddc4 100644 --- a/submodules/TelegramUI/Sources/NotificationContentContext.swift +++ b/submodules/TelegramUI/Sources/NotificationContentContext.swift @@ -238,10 +238,10 @@ public final class NotificationViewControllerImpl { return } if let imageReference = accountAndImage.1 { - strongSelf.imageNode.setSignal(chatMessagePhoto(postbox: accountAndImage.0.postbox, photoReference: imageReference)) + strongSelf.imageNode.setSignal(chatMessagePhoto(postbox: accountAndImage.0.postbox, userLocation: .other, photoReference: imageReference)) accountAndImage.0.network.shouldExplicitelyKeepWorkerConnections.set(.single(true)) - strongSelf.fetchedDisposable.set(standaloneChatMessagePhotoInteractiveFetched(account: accountAndImage.0, photoReference: imageReference).start()) + strongSelf.fetchedDisposable.set(standaloneChatMessagePhotoInteractiveFetched(account: accountAndImage.0, userLocation: .other, photoReference: imageReference).start()) } })) } else if let file = media as? TelegramMediaFile, let dimensions = file.dimensions { @@ -311,15 +311,15 @@ public final class NotificationViewControllerImpl { let dimensions = fileReference.media.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 512.0, height: 512.0)) if file.isVideoSticker { - strongSelf.imageNode.setSignal(chatMessageSticker(postbox: accountAndImage.0.postbox, file: fileReference.media, small: false)) + strongSelf.imageNode.setSignal(chatMessageSticker(postbox: accountAndImage.0.postbox, userLocation: .other, file: fileReference.media, small: false)) } else { - strongSelf.imageNode.setSignal(chatMessageAnimatedSticker(postbox: accountAndImage.0.postbox, file: fileReference.media, small: false, size: fittedDimensions)) + strongSelf.imageNode.setSignal(chatMessageAnimatedSticker(postbox: accountAndImage.0.postbox, userLocation: .other, file: fileReference.media, small: false, size: fittedDimensions)) } animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: accountAndImage.0, resource: fileReference.media.resource, isVideo: file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) animatedStickerNode.visibility = true accountAndImage.0.network.shouldExplicitelyKeepWorkerConnections.set(.single(true)) - strongSelf.fetchedDisposable.set(freeMediaFileInteractiveFetched(account: accountAndImage.0, fileReference: fileReference).start()) + strongSelf.fetchedDisposable.set(freeMediaFileInteractiveFetched(account: accountAndImage.0, userLocation: .other, fileReference: fileReference).start()) } else if file.isSticker { if let animatedStickerNode = strongSelf.animatedStickerNode { animatedStickerNode.removeFromSupernode() @@ -327,10 +327,10 @@ public final class NotificationViewControllerImpl { } strongSelf.imageNode.isHidden = false - strongSelf.imageNode.setSignal(chatMessageSticker(account: accountAndImage.0, file: file, small: false)) + strongSelf.imageNode.setSignal(chatMessageSticker(account: accountAndImage.0, userLocation: .other, file: file, small: false)) accountAndImage.0.network.shouldExplicitelyKeepWorkerConnections.set(.single(true)) - strongSelf.fetchedDisposable.set(freeMediaFileInteractiveFetched(account: accountAndImage.0, fileReference: fileReference).start()) + strongSelf.fetchedDisposable.set(freeMediaFileInteractiveFetched(account: accountAndImage.0, userLocation: .other, fileReference: fileReference).start()) } } })) diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index ba65a7fb87..0d17a3d37d 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -260,7 +260,9 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { func openChatInstantPage(context: AccountContext, message: Message, sourcePeerType: MediaAutoDownloadPeerType?, navigationController: NavigationController) { if let (webpage, anchor) = instantPageAndAnchor(message: message) { - let pageController = InstantPageController(context: context, webPage: webpage, sourcePeerType: sourcePeerType ?? .channel, anchor: anchor) + let sourceLocation = InstantPageSourceLocation(userLocation: .peer(message.id.peerId), peerType: sourcePeerType ?? .channel) + + let pageController = InstantPageController(context: context, webPage: webpage, sourceLocation: sourceLocation, anchor: anchor) navigationController.pushViewController(pageController) } } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index daf0fb0c56..3f89bac505 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -204,7 +204,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur }) present(controller, nil) case let .instantView(webpage, anchor): - navigationController?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)) + navigationController?.pushViewController(InstantPageController(context: context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: .other, peerType: .channel), anchor: anchor)) case let .join(link): dismissInput() present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in @@ -376,7 +376,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur subscriber.putNext((nil, settings, themeInfo)) subscriber.putCompletion() } else if let resource = themeInfo.file?.resource { - disposables.add(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: resource)).start()) + disposables.add(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .standalone(resource: resource)).start()) let maybeFetched = context.sharedContext.accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false) |> mapToSignal { maybeData -> Signal in diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index 100d99c963..109a5ad191 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -43,6 +43,7 @@ private final class FrameSequenceThumbnailNode: ASDisplayNode { init( context: AccountContext, + userLocation: MediaResourceUserLocation, file: FileMediaReference ) { self.context = context @@ -71,6 +72,8 @@ private final class FrameSequenceThumbnailNode: ASDisplayNode { let source = UniversalSoftwareVideoSource( mediaBox: self.context.account.postbox.mediaBox, + userLocation: userLocation, + userContentType: .gif, fileReference: self.file, automaticallyFetchHeader: true ) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index 7b789d031f..206becc8db 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -806,9 +806,6 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen let membersContext = PeerInfoMembersContext(context: context, peerId: groupId) membersData = combineLatest(membersContext.state, context.account.viewTracker.peerView(groupId, updateData: false)) |> map { state, view -> PeerInfoMembersData? in - if let cachedData = view.cachedData as? CachedChannelData, case let .known(value) = cachedData.membersHidden, value.value { - return nil - } if state.members.count > 5 { return .longList(membersContext) } else { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 30d719f700..cebc720371 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -514,7 +514,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { if threadInfo == nil, let video = videoRepresentations.last, let peerReference = PeerReference(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(videoId, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: peer.isCopyProtectionEnabled) + let videoContent = NativeVideoContent(id: .profileVideo(videoId, nil), userLocation: .other, fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: peer.isCopyProtectionEnabled) if videoContent.id != self.videoContent?.id { self.videoNode?.removeFromSupernode() @@ -844,7 +844,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode { if threadData == nil, let video = videoRepresentations.last, let peerReference = PeerReference(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: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: peer.isCopyProtectionEnabled) + 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: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear, captureProtected: peer.isCopyProtectionEnabled) if videoContent.id != self.videoContent?.id { self.videoNode?.removeFromSupernode() diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift index 831fb5442c..df3d35aca6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift @@ -131,6 +131,7 @@ private final class PeerInfoMembersContextImpl { private var members: [PeerInfoMember] = [] private var dataState: PeerInfoMembersDataState = .loading(isInitial: true) private var removingMemberIds: [PeerId: Disposable] = [:] + private var membersHidden: Bool? private let stateValue = Promise() var state: Signal { @@ -148,7 +149,7 @@ private final class PeerInfoMembersContextImpl { self.pushState() if peerId.namespace == Namespaces.Peer.CloudChannel { - let (disposable, control) = context.peerChannelMemberCategoriesContextsManager.recent(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, updated: { [weak self] state in + let (disposable, control) = context.peerChannelMemberCategoriesContextsManager.recent(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, requestUpdate: true, updated: { [weak self] state in queue.async { guard let strongSelf = self else { return @@ -178,6 +179,7 @@ private final class PeerInfoMembersContextImpl { guard let strongSelf = self else { return } + if let channel = peerViewMainPeer(view) as? TelegramChannel { var canAddMembers = false switch channel.info { @@ -191,6 +193,20 @@ private final class PeerInfoMembersContextImpl { strongSelf.canAddMembers = canAddMembers strongSelf.pushState() } + + var membersHidden: Bool? + if let cachedData = view.cachedData as? CachedChannelData, case let .known(value) = cachedData.membersHidden { + membersHidden = value.value + } + + if strongSelf.membersHidden != membersHidden { + let shouldResetList = strongSelf.membersHidden != nil + strongSelf.membersHidden = membersHidden + + if shouldResetList, let control = strongSelf.channelMembersControl { + context.peerChannelMemberCategoriesContextsManager.reset(peerId: peerId, control: control) + } + } })) } else if peerId.namespace == Namespaces.Peer.CloudGroup { self.disposable.set((context.account.postbox.peerView(id: peerId) diff --git a/submodules/TelegramUI/Sources/PeerInfoGifPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfoGifPaneNode.swift index 098d790c02..47ba634666 100644 --- a/submodules/TelegramUI/Sources/PeerInfoGifPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfoGifPaneNode.swift @@ -34,6 +34,7 @@ private final class FrameSequenceThumbnailNode: ASDisplayNode { init( context: AccountContext, + userLocation: MediaResourceUserLocation, file: FileMediaReference ) { self.context = context @@ -62,6 +63,8 @@ private final class FrameSequenceThumbnailNode: ASDisplayNode { let source = UniversalSoftwareVideoSource( mediaBox: self.context.account.postbox.mediaBox, + userLocation: userLocation, + userContentType: .gif, fileReference: self.file, automaticallyFetchHeader: true ) @@ -297,7 +300,7 @@ private final class VisualMediaItemNode: ASDisplayNode { self.imageNode.layer.addSublayer(sampleBufferLayer.layer) } - self.videoLayerFrameManager = SoftwareVideoLayerFrameManager(account: self.context.account, fileReference: FileMediaReference.message(message: MessageReference(item.message), media: file), layerHolder: sampleBufferLayer) + self.videoLayerFrameManager = SoftwareVideoLayerFrameManager(account: self.context.account, userLocation: .peer(item.message.id.peerId), userContentType: .gif, fileReference: FileMediaReference.message(message: MessageReference(item.message), media: file), layerHolder: sampleBufferLayer) self.videoLayerFrameManager?.start() } } else { @@ -313,7 +316,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(item.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(item.message.id.peerId), photoReference: .message(message: MessageReference(item.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 @@ -323,7 +326,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(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) + self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(item.message.id.peerId), videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) self.mediaBadgeNode.isHidden = file.isAnimated diff --git a/submodules/TelegramUI/Sources/PrefetchManager.swift b/submodules/TelegramUI/Sources/PrefetchManager.swift index b0d2f47c75..202b5da7bb 100644 --- a/submodules/TelegramUI/Sources/PrefetchManager.swift +++ b/submodules/TelegramUI/Sources/PrefetchManager.swift @@ -182,7 +182,7 @@ private final class PrefetchManagerInnerImpl { } } else if case .prefetch = automaticDownload, mediaItem.media.peer.id.namespace != Namespaces.Peer.SecretChat { if let file = media as? TelegramMediaFile, let _ = file.size { - context.fetchDisposable.set(preloadVideoResource(postbox: self.account.postbox, resourceReference: FileMediaReference.message(message: MessageReference(peer: mediaItem.media.peer, author: nil, id: mediaItem.media.index.id, timestamp: mediaItem.media.index.timestamp, incoming: true, secret: false), media: file).resourceReference(file.resource), duration: 4.0).start()) + context.fetchDisposable.set(preloadVideoResource(postbox: self.account.postbox, userLocation: .peer(mediaItem.media.index.id.peerId), userContentType: MediaResourceUserContentType(file: file), resourceReference: FileMediaReference.message(message: MessageReference(peer: mediaItem.media.peer, author: nil, id: mediaItem.media.index.id, timestamp: mediaItem.media.index.timestamp, incoming: true, secret: false), media: file).resourceReference(file.resource), duration: 4.0).start()) } } } @@ -249,7 +249,7 @@ private final class PrefetchManagerInnerImpl { self.preloadGreetingStickerDisposable.set((self.preloadedGreetingStickerPromise.get() |> mapToSignal { sticker -> Signal in if let sticker = sticker { - let _ = freeMediaFileInteractiveFetched(account: account, fileReference: .standalone(media: sticker)).start() + let _ = freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: sticker)).start() return chatMessageAnimationData(mediaBox: account.postbox.mediaBox, resource: sticker.resource, fitzModifier: nil, isVideo: sticker.isVideoSticker, width: 384, height: 384, synchronousLoad: false) |> mapToSignal { _ -> Signal in return .complete() diff --git a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift index ee26fb232c..523163d969 100644 --- a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift @@ -209,12 +209,12 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { if mediaUpdated { if let updatedMediaReference = updatedMediaReference, imageDimensions != nil { if let imageReference = updatedMediaReference.concrete(TelegramMediaImage.self) { - updateImageSignal = chatMessagePhotoThumbnail(account: context.account, photoReference: imageReference) + updateImageSignal = chatMessagePhotoThumbnail(account: context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, photoReference: imageReference) } else if let fileReference = updatedMediaReference.concrete(TelegramMediaFile.self) { if fileReference.media.isVideo { - updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) + updateImageSignal = chatMessageVideoThumbnail(account: context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, fileReference: fileReference) } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { - updateImageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation) + updateImageSignal = chatWebpageSnippetFile(account: context.account, userLocation: (message?.id.peerId).flatMap(MediaResourceUserLocation.peer) ?? .other, mediaReference: fileReference.abstract, representation: iconImageRepresentation) } } } else { diff --git a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift index 12038021d6..d9ccccc336 100644 --- a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift +++ b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift @@ -228,13 +228,13 @@ final class SharedMediaPlayer { case .voice, .music: switch playbackData.source { case let .telegramFile(fileReference, _): - strongSelf.playbackItem = .audio(MediaPlayer(audioSessionManager: strongSelf.audioSession, postbox: strongSelf.account.postbox, resourceReference: fileReference.resourceReference(fileReference.media.resource), streamable: playbackData.type == .music ? .conservative : .none, video: false, preferSoftwareDecoding: false, enableSound: true, baseRate: rateValue, fetchAutomatically: true, playAndRecord: controlPlaybackWithProximity)) + strongSelf.playbackItem = .audio(MediaPlayer(audioSessionManager: strongSelf.audioSession, postbox: strongSelf.account.postbox, userLocation: .other, userContentType: .audio, resourceReference: fileReference.resourceReference(fileReference.media.resource), streamable: playbackData.type == .music ? .conservative : .none, video: false, preferSoftwareDecoding: false, enableSound: true, baseRate: rateValue, fetchAutomatically: true, playAndRecord: controlPlaybackWithProximity)) } case .instantVideo: if let mediaManager = strongSelf.mediaManager, let item = item as? MessageMediaPlaylistItem { switch playbackData.source { case let .telegramFile(fileReference, _): - let videoNode = OverlayInstantVideoNode(postbox: strongSelf.account.postbox, audioSession: strongSelf.audioSession, manager: mediaManager.universalVideoManager, content: NativeVideoContent(id: .message(item.message.stableId, fileReference.media.fileId), fileReference: fileReference, enableSound: false, baseRate: rateValue, captureProtected: item.message.isCopyProtected()), close: { [weak mediaManager] in + let videoNode = OverlayInstantVideoNode(postbox: strongSelf.account.postbox, audioSession: strongSelf.audioSession, manager: mediaManager.universalVideoManager, content: NativeVideoContent(id: .message(item.message.stableId, fileReference.media.fileId), userLocation: .peer(item.message.id.peerId), fileReference: fileReference, enableSound: false, baseRate: rateValue, captureProtected: item.message.isCopyProtected()), close: { [weak mediaManager] in mediaManager?.setPlaylist(nil, type: .voice, control: .playback(.pause)) }) strongSelf.playbackItem = .instantVideo(videoNode) @@ -497,7 +497,7 @@ final class SharedMediaPlayer { } switch next { case let .telegramFile(file, _): - fetchedNextSignal = fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, reference: file.resourceReference(file.media.resource)) + fetchedNextSignal = fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, userLocation: .other, userContentType: .audio, reference: file.resourceReference(file.media.resource)) |> ignoreValues |> `catch` { _ -> Signal in return .complete() diff --git a/submodules/TelegramUI/Sources/SoftwareVideoThumbnailLayer.swift b/submodules/TelegramUI/Sources/SoftwareVideoThumbnailLayer.swift index e54058df92..6e546c4b2f 100644 --- a/submodules/TelegramUI/Sources/SoftwareVideoThumbnailLayer.swift +++ b/submodules/TelegramUI/Sources/SoftwareVideoThumbnailLayer.swift @@ -52,7 +52,7 @@ final class SoftwareVideoThumbnailNode: ASDisplayNode { self.layer.masksToBounds = true if let dimensions = fileReference.media.dimensions { - self.disposable.set((mediaGridMessageVideo(postbox: account.postbox, videoReference: fileReference, synchronousLoad: synchronousLoad, nilForEmptyResult: true) + self.disposable.set((mediaGridMessageVideo(postbox: account.postbox, userLocation: .other, videoReference: fileReference, synchronousLoad: synchronousLoad, nilForEmptyResult: true) |> deliverOnMainQueue).start(next: { [weak self] transform in var boundingSize = dimensions.cgSize.aspectFilled(CGSize(width: 93.0, height: 93.0)) let imageSize = boundingSize diff --git a/submodules/TelegramUI/Sources/StickerPaneSearchStickerItem.swift b/submodules/TelegramUI/Sources/StickerPaneSearchStickerItem.swift index 158cb2b2a4..86ea0bf87e 100644 --- a/submodules/TelegramUI/Sources/StickerPaneSearchStickerItem.swift +++ b/submodules/TelegramUI/Sources/StickerPaneSearchStickerItem.swift @@ -167,15 +167,15 @@ final class StickerPaneSearchStickerItemNode: GridItemNode { let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached) self.animationNode?.visibility = self.isVisibleInGrid - 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()) } else { if let animationNode = self.animationNode { animationNode.visibility = false 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()) } self.currentState = (account, stickerItem, dimensions.cgSize) diff --git a/submodules/TelegramUI/Sources/StickerPaneTrendingListGridItem.swift b/submodules/TelegramUI/Sources/StickerPaneTrendingListGridItem.swift index a7793b474b..edaa9224c7 100644 --- a/submodules/TelegramUI/Sources/StickerPaneTrendingListGridItem.swift +++ b/submodules/TelegramUI/Sources/StickerPaneTrendingListGridItem.swift @@ -310,7 +310,7 @@ private final class FeaturedPackItemNode: ListViewItemNode { animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers } if let resourceReference = resourceReference { - self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start()) + self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference).start()) } } } diff --git a/submodules/TelegramUI/Sources/StickersChatInputContextPanelItem.swift b/submodules/TelegramUI/Sources/StickersChatInputContextPanelItem.swift index 2ee6fa30c7..9756e35f08 100644 --- a/submodules/TelegramUI/Sources/StickersChatInputContextPanelItem.swift +++ b/submodules/TelegramUI/Sources/StickersChatInputContextPanelItem.swift @@ -219,8 +219,8 @@ final class StickersChatInputContextPanelItemNode: ListViewItemNode { strongSelf.addSubnode(imageNode) } - imageNode.setSignal(chatMessageSticker(account: item.account, file: file, small: true)) - strongSelf.disposables.add(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(file), resource: chatMessageStickerResource(file: file, small: true)).start()) + imageNode.setSignal(chatMessageSticker(account: item.account, userLocation: .other, file: file, small: true)) + strongSelf.disposables.add(freeMediaFileResourceInteractiveFetched(account: item.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: chatMessageStickerResource(file: file, small: true)).start()) var imageSize = itemSize if let dimensions = file.dimensions { diff --git a/submodules/TelegramUI/Sources/TextLinkHandling.swift b/submodules/TelegramUI/Sources/TextLinkHandling.swift index ef18282655..63c96cff23 100644 --- a/submodules/TelegramUI/Sources/TextLinkHandling.swift +++ b/submodules/TelegramUI/Sources/TextLinkHandling.swift @@ -80,7 +80,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate let packReference: StickerPackReference = .name(name) controller.present(StickerPackScreen(context: context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root)) case let .instantView(webpage, anchor): - (controller.navigationController as? NavigationController)?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .group, anchor: anchor)) + (controller.navigationController as? NavigationController)?.pushViewController(InstantPageController(context: context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, peerType: .group), anchor: anchor)) case let .join(link): controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in openResolvedPeerImpl(peer, .chat(textInputState: nil, subject: nil, peekData: peekData)) diff --git a/submodules/TelegramUI/Sources/TransformOutgoingMessageMedia.swift b/submodules/TelegramUI/Sources/TransformOutgoingMessageMedia.swift index 9aa4182481..2b20f1e525 100644 --- a/submodules/TelegramUI/Sources/TransformOutgoingMessageMedia.swift +++ b/submodules/TelegramUI/Sources/TransformOutgoingMessageMedia.swift @@ -11,7 +11,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me switch media.media { case let file as TelegramMediaFile: let signal = Signal { subscriber in - let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: media.resourceReference(file.resource)).start() + let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: MediaResourceUserContentType(file: file), reference: media.resourceReference(file.resource)).start() let data = postbox.mediaBox.resourceData(file.resource, option: .complete(waitUntilFetchStatus: true)).start(next: { next in subscriber.putNext(next) if next.complete { @@ -127,7 +127,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me case let image as TelegramMediaImage: if let representation = largestImageRepresentation(image.representations) { let signal = Signal { subscriber in - let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: media.resourceReference(representation.resource)).start() + let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .image, reference: media.resourceReference(representation.resource)).start() let data = postbox.mediaBox.resourceData(representation.resource, option: .complete(waitUntilFetchStatus: true)).start(next: { next in subscriber.putNext(next) if next.complete { diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift index bddeb12d65..5b21e49273 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift @@ -248,11 +248,11 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode { if updatedIconImageResource { if let imageResource = imageResource { if let stickerFile = stickerFile { - updateIconImageSignal = chatMessageSticker(account: item.account, file: stickerFile, small: false, fetched: true) + updateIconImageSignal = chatMessageSticker(account: item.account, userLocation: .other, file: stickerFile, small: false, fetched: true) } else { let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 55, height: 55), resource: imageResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false) let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []) - updateIconImageSignal = chatWebpageSnippetPhoto(account: item.account, photoReference: .standalone(media: tmpImage)) + updateIconImageSignal = chatWebpageSnippetPhoto(account: item.account, userLocation: .other, photoReference: .standalone(media: tmpImage)) } } else { updateIconImageSignal = .complete() diff --git a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift index 21d13bf3cb..9df648a465 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift @@ -28,6 +28,7 @@ public enum NativeVideoContentId: Hashable { public final class NativeVideoContent: UniversalVideoContent { public let id: AnyHashable public let nativeId: NativeVideoContentId + public let userLocation: MediaResourceUserLocation public let fileReference: FileMediaReference let imageReference: ImageMediaReference? public let dimensions: CGSize @@ -48,9 +49,10 @@ public final class NativeVideoContent: UniversalVideoContent { let captureProtected: Bool let hintDimensions: CGSize? - public init(id: NativeVideoContentId, fileReference: FileMediaReference, imageReference: ImageMediaReference? = nil, streamVideo: MediaPlayerStreaming = .none, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true, onlyFullSizeThumbnail: Bool = false, useLargeThumbnail: Bool = false, autoFetchFullSizeThumbnail: Bool = false, startTimestamp: Double? = nil, endTimestamp: Double? = nil, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor = .white, tempFilePath: String? = nil, captureProtected: Bool = false, hintDimensions: CGSize? = nil) { + public init(id: NativeVideoContentId, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, imageReference: ImageMediaReference? = nil, streamVideo: MediaPlayerStreaming = .none, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true, onlyFullSizeThumbnail: Bool = false, useLargeThumbnail: Bool = false, autoFetchFullSizeThumbnail: Bool = false, startTimestamp: Double? = nil, endTimestamp: Double? = nil, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor = .white, tempFilePath: String? = nil, captureProtected: Bool = false, hintDimensions: CGSize? = nil) { self.id = id self.nativeId = id + self.userLocation = userLocation self.fileReference = fileReference self.imageReference = imageReference if var dimensions = fileReference.media.dimensions { @@ -85,7 +87,7 @@ public final class NativeVideoContent: UniversalVideoContent { } public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { - return NativeVideoContentNode(postbox: postbox, audioSessionManager: audioSession, fileReference: self.fileReference, imageReference: self.imageReference, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically, onlyFullSizeThumbnail: self.onlyFullSizeThumbnail, useLargeThumbnail: self.useLargeThumbnail, autoFetchFullSizeThumbnail: self.autoFetchFullSizeThumbnail, startTimestamp: self.startTimestamp, endTimestamp: self.endTimestamp, continuePlayingWithoutSoundOnLostAudioSession: self.continuePlayingWithoutSoundOnLostAudioSession, placeholderColor: self.placeholderColor, tempFilePath: self.tempFilePath, captureProtected: self.captureProtected, hintDimensions: self.hintDimensions) + return NativeVideoContentNode(postbox: postbox, audioSessionManager: audioSession, userLocation: self.userLocation, fileReference: self.fileReference, imageReference: self.imageReference, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically, onlyFullSizeThumbnail: self.onlyFullSizeThumbnail, useLargeThumbnail: self.useLargeThumbnail, autoFetchFullSizeThumbnail: self.autoFetchFullSizeThumbnail, startTimestamp: self.startTimestamp, endTimestamp: self.endTimestamp, continuePlayingWithoutSoundOnLostAudioSession: self.continuePlayingWithoutSoundOnLostAudioSession, placeholderColor: self.placeholderColor, tempFilePath: self.tempFilePath, captureProtected: self.captureProtected, hintDimensions: self.hintDimensions) } public func isEqual(to other: UniversalVideoContent) -> Bool { @@ -104,6 +106,7 @@ public final class NativeVideoContent: UniversalVideoContent { private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContentNode { private let postbox: Postbox + private let userLocation: MediaResourceUserLocation private let fileReference: FileMediaReference private let enableSound: Bool private let loopVideo: Bool @@ -159,8 +162,9 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent private var shouldPlay: Bool = false - init(postbox: Postbox, audioSessionManager: ManagedAudioSession, fileReference: FileMediaReference, imageReference: ImageMediaReference?, streamVideo: MediaPlayerStreaming, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, onlyFullSizeThumbnail: Bool, useLargeThumbnail: Bool, autoFetchFullSizeThumbnail: Bool, startTimestamp: Double?, endTimestamp: Double?, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor, tempFilePath: String?, captureProtected: Bool, hintDimensions: CGSize?) { + init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, imageReference: ImageMediaReference?, streamVideo: MediaPlayerStreaming, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, onlyFullSizeThumbnail: Bool, useLargeThumbnail: Bool, autoFetchFullSizeThumbnail: Bool, startTimestamp: Double?, endTimestamp: Double?, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor, tempFilePath: String?, captureProtected: Bool, hintDimensions: CGSize?) { self.postbox = postbox + self.userLocation = userLocation self.fileReference = fileReference self.placeholderColor = placeholderColor self.enableSound = enableSound @@ -171,7 +175,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent self.imageNode = TransformImageNode() - self.player = MediaPlayer(audioSessionManager: audioSessionManager, postbox: postbox, resourceReference: fileReference.resourceReference(fileReference.media.resource), tempFilePath: tempFilePath, streamable: streamVideo, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession) + self.player = MediaPlayer(audioSessionManager: audioSessionManager, postbox: postbox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), resourceReference: fileReference.resourceReference(fileReference.media.resource), tempFilePath: tempFilePath, streamable: streamVideo, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession) var actionAtEndImpl: (() -> Void)? if enableSound && !loopVideo { @@ -202,7 +206,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent self?.performActionAtEnd() } - self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, videoReference: fileReference, imageReference: imageReference, onlyFullSize: onlyFullSizeThumbnail, useLargeThumbnail: useLargeThumbnail, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail || fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in + self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: fileReference, imageReference: imageReference, onlyFullSize: onlyFullSizeThumbnail, useLargeThumbnail: useLargeThumbnail, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail || fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in Queue.mainQueue().async { if let strongSelf = self, strongSelf.dimensions == nil { if let dimensions = getSize() { @@ -268,7 +272,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent return } - let thumbnailPlayer = MediaPlayer(audioSessionManager: self.audioSessionManager, postbox: postbox, resourceReference: fileReference.resourceReference(videoThumbnail.resource), tempFilePath: nil, streamable: .none, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: false, baseRate: self.baseRate, fetchAutomatically: false, continuePlayingWithoutSoundOnLostAudioSession: false) + let thumbnailPlayer = MediaPlayer(audioSessionManager: self.audioSessionManager, postbox: postbox, userLocation: self.userLocation, userContentType: MediaResourceUserContentType(file: self.fileReference.media), resourceReference: self.fileReference.resourceReference(videoThumbnail.resource), tempFilePath: nil, streamable: .none, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: false, baseRate: self.baseRate, fetchAutomatically: false, continuePlayingWithoutSoundOnLostAudioSession: false) self.thumbnailPlayer = thumbnailPlayer var actionAtEndImpl: (() -> Void)? @@ -466,7 +470,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent func fetchControl(_ control: UniversalVideoNodeFetchControl) { switch control { case .fetch: - self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.postbox.mediaBox, reference: self.fileReference.resourceReference(self.fileReference.media.resource), statsCategory: statsCategoryForFileWithAttributes(self.fileReference.media.attributes)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.postbox.mediaBox, userLocation: self.userLocation, userContentType: .video, reference: self.fileReference.resourceReference(self.fileReference.media.resource), statsCategory: statsCategoryForFileWithAttributes(self.fileReference.media.attributes)).start()) case .cancel: self.postbox.mediaBox.cancelInteractiveResourceFetch(self.fileReference.media.resource) } diff --git a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift index c29914a891..4caf93fbb2 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift @@ -71,6 +71,7 @@ public final class PlatformVideoContent: UniversalVideoContent { public let id: AnyHashable let nativeId: PlatformVideoContentId + let userLocation: MediaResourceUserLocation let content: Content public let dimensions: CGSize public let duration: Int32 @@ -80,8 +81,9 @@ public final class PlatformVideoContent: UniversalVideoContent { let baseRate: Double let fetchAutomatically: Bool - public init(id: PlatformVideoContentId, content: Content, streamVideo: Bool = false, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true) { + public init(id: PlatformVideoContentId, userLocation: MediaResourceUserLocation, content: Content, streamVideo: Bool = false, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true) { self.id = id + self.userLocation = userLocation self.nativeId = id self.content = content self.dimensions = self.content.dimensions?.cgSize ?? CGSize(width: 480, height: 320) @@ -94,7 +96,7 @@ public final class PlatformVideoContent: UniversalVideoContent { } public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { - return PlatformVideoContentNode(postbox: postbox, audioSessionManager: audioSession, content: self.content, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically) + return PlatformVideoContentNode(postbox: postbox, audioSessionManager: audioSession, userLocation: self.userLocation, content: self.content, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically) } public func isEqual(to other: UniversalVideoContent) -> Bool { @@ -115,6 +117,7 @@ public final class PlatformVideoContent: UniversalVideoContent { private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoContentNode { private let postbox: Postbox + private let userLocation: MediaResourceUserLocation private let content: PlatformVideoContent.Content private let approximateDuration: Double private let intrinsicDimensions: CGSize @@ -169,11 +172,12 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte private var validLayout: CGSize? - init(postbox: Postbox, audioSessionManager: ManagedAudioSession, content: PlatformVideoContent.Content, streamVideo: Bool, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool) { + init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, content: PlatformVideoContent.Content, streamVideo: Bool, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool) { self.postbox = postbox self.content = content self.approximateDuration = Double(content.duration ?? 1) self.audioSessionManager = audioSessionManager + self.userLocation = userLocation self.imageNode = TransformImageNode() @@ -193,7 +197,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte switch content { case let .file(file): - self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, videoReference: file) |> map { [weak self] getSize, getData in + self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, userLocation: self.userLocation, videoReference: file) |> map { [weak self] getSize, getData in Queue.mainQueue().async { if let strongSelf = self, strongSelf.dimensions == nil { if let dimensions = getSize() { diff --git a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift index 643a93c7fd..4e7e45cd93 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift @@ -14,21 +14,23 @@ import RangeSet public final class SystemVideoContent: UniversalVideoContent { public let id: AnyHashable + let userLocation: MediaResourceUserLocation let url: String let imageReference: ImageMediaReference public let dimensions: CGSize public let duration: Int32 - public init(url: String, imageReference: ImageMediaReference, dimensions: CGSize, duration: Int32) { + public init(userLocation: MediaResourceUserLocation, url: String, imageReference: ImageMediaReference, dimensions: CGSize, duration: Int32) { self.id = AnyHashable(url) self.url = url + self.userLocation = userLocation self.imageReference = imageReference self.dimensions = dimensions self.duration = duration } public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { - return SystemVideoContentNode(postbox: postbox, audioSessionManager: audioSession, url: self.url, imageReference: self.imageReference, intrinsicDimensions: self.dimensions, approximateDuration: self.duration) + return SystemVideoContentNode(postbox: postbox, audioSessionManager: audioSession, userLocation: self.userLocation, url: self.url, imageReference: self.imageReference, intrinsicDimensions: self.dimensions, approximateDuration: self.duration) } } @@ -81,7 +83,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent private var seekId: Int = 0 - init(postbox: Postbox, audioSessionManager: ManagedAudioSession, url: String, imageReference: ImageMediaReference, intrinsicDimensions: CGSize, approximateDuration: Int32) { + init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, url: String, imageReference: ImageMediaReference, intrinsicDimensions: CGSize, approximateDuration: Int32) { self.audioSessionManager = audioSessionManager self.url = url @@ -104,7 +106,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent super.init() - self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, photoReference: imageReference)) + self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, userLocation: userLocation, photoReference: imageReference)) self.addSubnode(self.imageNode) self.addSubnode(self.playerNode) diff --git a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift index 906645d531..f95d913ed1 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift @@ -14,6 +14,7 @@ import RangeSet public final class WebEmbedVideoContent: UniversalVideoContent { public let id: AnyHashable + let userLocation: MediaResourceUserLocation let webPage: TelegramMediaWebpage public let webpageContent: TelegramMediaWebpageLoadedContent public let dimensions: CGSize @@ -21,11 +22,12 @@ public final class WebEmbedVideoContent: UniversalVideoContent { let forcedTimestamp: Int? let openUrl: (URL) -> Void - public init?(webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) { + public init?(userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) { guard let embedUrl = webpageContent.embedUrl else { return nil } self.id = AnyHashable(embedUrl) + self.userLocation = userLocation self.webPage = webPage self.webpageContent = webpageContent self.dimensions = webpageContent.embedSize?.cgSize ?? CGSize(width: 128.0, height: 128.0) @@ -35,7 +37,7 @@ public final class WebEmbedVideoContent: UniversalVideoContent { } public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { - return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, webPage: self.webPage, webpageContent: self.webpageContent, forcedTimestamp: self.forcedTimestamp, openUrl: self.openUrl) + return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, userLocation: self.userLocation, webPage: self.webPage, webpageContent: self.webpageContent, forcedTimestamp: self.forcedTimestamp, openUrl: self.openUrl) } } @@ -72,7 +74,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode { private var readyDisposable = MetaDisposable() - init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) { + init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) { self.webpageContent = webpageContent if let embedSize = webpageContent.embedSize { @@ -93,7 +95,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode { self.addSubnode(self.imageNode) if let image = webpageContent.image { - self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, photoReference: .webPage(webPage: WebpageReference(webPage), media: image))) + self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, userLocation: userLocation, photoReference: .webPage(webPage: WebpageReference(webPage), media: image))) self.imageNode.imageUpdated = { [weak self] _ in self?._ready.set(.single(Void())) } diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index f0cc626665..29eecd4401 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -415,7 +415,7 @@ public final class OngoingGroupCallContext { private final class Impl { let queue: Queue let context: GroupCallThreadLocalContext - // let audioDevice: SharedCallAudioDevice? + let audioDevice: SharedCallAudioDevice? let sessionId = UInt32.random(in: 0 ..< UInt32(Int32.max)) let joinPayload = Promise<(String, UInt32)>() @@ -433,8 +433,8 @@ public final class OngoingGroupCallContext { init(queue: Queue, inputDeviceId: String, outputDeviceId: String, audioSessionActive: Signal, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) { self.queue = queue -// self.audioDevice = nil -// let audioDevice = self.audioDevice + self.audioDevice = nil + let audioDevice = self.audioDevice var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)? var audioLevelsUpdatedImpl: (([NSNumber]) -> Void)? @@ -541,8 +541,8 @@ public final class OngoingGroupCallContext { enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, preferX264: preferX264, - logPath: logPath -// audioDevice: audioDevice + logPath: logPath, + audioDevice: audioDevice ) let queue = self.queue diff --git a/submodules/TemporaryCachedPeerDataManager/Sources/ChannelMemberCategoryListContext.swift b/submodules/TemporaryCachedPeerDataManager/Sources/ChannelMemberCategoryListContext.swift index ea2b6a8360..fb879ae51f 100644 --- a/submodules/TemporaryCachedPeerDataManager/Sources/ChannelMemberCategoryListContext.swift +++ b/submodules/TemporaryCachedPeerDataManager/Sources/ChannelMemberCategoryListContext.swift @@ -630,7 +630,7 @@ private final class ChannelMemberMultiCategoryListContext: ChannelMemberCategory } public struct PeerChannelMemberCategoryControl { - fileprivate let key: PeerChannelMemberContextKey + let key: PeerChannelMemberContextKey } private final class PeerChannelMemberContextWithSubscribers { diff --git a/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift b/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift index 32a057e698..c410435c02 100644 --- a/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift +++ b/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift @@ -147,6 +147,12 @@ private final class PeerChannelMemberCategoriesContextsManagerImpl { } } + func reset(peerId: PeerId, control: PeerChannelMemberCategoryControl) { + if let context = self.contexts[peerId] { + context.reset(control.key) + } + } + func profileData(postbox: Postbox, network: Network, peerId: PeerId, customData: Signal?) -> Disposable { let context: ProfileDataPreloadContext if let current = self.profileDataPreloadContexts[peerId] { @@ -285,6 +291,12 @@ public final class PeerChannelMemberCategoriesContextsManager { } } + public func reset(peerId: PeerId, control: PeerChannelMemberCategoryControl) { + self.impl.with { impl in + impl.reset(peerId: peerId, control: control) + } + } + private func getContext(engine: TelegramEngine, postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, key: PeerChannelMemberContextKey, requestUpdate: Bool, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl?) { assert(Queue.mainQueue().isCurrent()) let (disposable, control) = self.impl.syncWith({ impl in diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index d386c49631..2f773d98bd 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit d386c496314966eabd363452a90bf9a819fcb293 +Subproject commit 2f773d98bdfd60d55247b2b3adb8ec70a1fc5748 diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index 35b3a240a8..6de7463e12 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -407,7 +407,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: resource._asResource(), animated: true) } if let resourceReference = resourceReference { - updatedFetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: resourceReference) + updatedFetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: resourceReference) |> mapError { _ -> EngineMediaResource.Fetch.Error in return .generic } @@ -689,7 +689,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: resource._asResource(), animated: true) } if let resourceReference = resourceReference { - updatedFetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: resourceReference) + updatedFetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: resourceReference) |> mapError { _ -> EngineMediaResource.Fetch.Error in return .generic } diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index d928740173..ed96b11a3b 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -1619,7 +1619,7 @@ final class WallpaperBackgroundNodeMergedImpl: ASDisplayNode, WallpaperBackgroun switch spec { case let .image(representation, _, _): - self.fetchDisposable = (fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: MediaResourceReference.standalone(resource: representation.resource)) + self.fetchDisposable = (fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: MediaResourceReference.standalone(resource: representation.resource)) |> deliverOnMainQueue).start() self.dataDisposable = (context.account.postbox.mediaBox.resourceData(representation.resource) |> deliverOnMainQueue).start(next: { [weak self] dataValue in diff --git a/submodules/WallpaperResources/Sources/WallpaperResources.swift b/submodules/WallpaperResources/Sources/WallpaperResources.swift index 61b01775f7..e48af8b463 100644 --- a/submodules/WallpaperResources/Sources/WallpaperResources.swift +++ b/submodules/WallpaperResources/Sources/WallpaperResources.swift @@ -88,9 +88,9 @@ public func wallpaperDatas(account: Account, accountManager: AccountManager - fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference) + fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, 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: .other, reference: representations[largestIndex].reference) let thumbnailData: Signal @@ -395,7 +395,7 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single((loadedData, true)) } else { - let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: targetRepresentation.reference) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: targetRepresentation.reference) let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in let fetchedFullSizeDisposable = fetchedFullSize.start() @@ -907,7 +907,7 @@ public func telegramThemeData(account: Account, accountManager: AccountManager map { data -> Data? in return data.complete ? try? Data(contentsOf: URL(fileURLWithPath: data.path)) : nil @@ -1117,7 +1117,7 @@ public func themeImage(account: Account, accountManager: AccountManager if let previewRepresentation = previewRepresentation { - fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(previewRepresentation.resource)) + fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: fileReference.resourceReference(previewRepresentation.resource)) } else { fetchedThumbnail = .complete() } @@ -1148,7 +1148,7 @@ public func themeImage(account: Account, accountManager: AccountManager if isSupportedTheme { fullSizeData = Signal { subscriber in - let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: reference).start() + let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: reference).start() let disposable = (account.postbox.mediaBox.resourceData(reference.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false) |> map { data -> Data? in return data.complete ? try? Data(contentsOf: URL(fileURLWithPath: data.path)) : nil @@ -1775,7 +1775,7 @@ public func wallpaperThumbnail(account: Account, accountManager: AccountManager< } } }) - let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnail.resource)).start() + let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: fileReference.resourceReference(thumbnail.resource)).start() return ActionDisposable { data.dispose() diff --git a/submodules/WatchBridge/Sources/WatchRequestHandlers.swift b/submodules/WatchBridge/Sources/WatchRequestHandlers.swift index 8b8edc4cf5..34185fc23b 100644 --- a/submodules/WatchBridge/Sources/WatchRequestHandlers.swift +++ b/submodules/WatchBridge/Sources/WatchRequestHandlers.swift @@ -476,8 +476,8 @@ final class WatchMediaHandler: WatchRequestHandler { if let dimensions = media.dimensions { size = dimensions.cgSize } - self.disposable.add(freeMediaFileInteractiveFetched(account: context.account, fileReference: fileReference).start()) - return chatMessageSticker(account: context.account, file: media, small: false, fetched: true, onlyFullSize: true) + self.disposable.add(freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: fileReference).start()) + return chatMessageSticker(account: context.account, userLocation: .other, file: media, small: false, fetched: true, onlyFullSize: true) } return .complete() } @@ -545,13 +545,13 @@ final class WatchMediaHandler: WatchRequestHandler { } if let updatedMediaReference = updatedMediaReference, imageDimensions != nil { if let imageReference = updatedMediaReference.concrete(TelegramMediaImage.self) { - imageSignal = chatMessagePhotoThumbnail(account: context.account, photoReference: imageReference, onlyFullSize: true) + imageSignal = chatMessagePhotoThumbnail(account: context.account, userLocation: .other, photoReference: imageReference, onlyFullSize: true) } else if let fileReference = updatedMediaReference.concrete(TelegramMediaFile.self) { if fileReference.media.isVideo { - imageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) + imageSignal = chatMessageVideoThumbnail(account: context.account, userLocation: .other, fileReference: fileReference) roundVideo = fileReference.media.isInstantVideo } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { - imageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation) + imageSignal = chatWebpageSnippetFile(account: context.account, userLocation: .other, mediaReference: fileReference.abstract, representation: iconImageRepresentation) } } } diff --git a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift index d1598463f5..f05d45a489 100644 --- a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift +++ b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift @@ -264,7 +264,7 @@ func legacyWebSearchItem(account: Account, result: ChatContextResult) -> LegacyW } representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) let tmpImage = TelegramMediaImage(imageId: EngineMedia.Id(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: []) - thumbnailSignal = chatMessagePhotoDatas(postbox: account.postbox, photoReference: .standalone(media: tmpImage), autoFetchFullSize: false) + thumbnailSignal = chatMessagePhotoDatas(postbox: account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage), autoFetchFullSize: false) |> mapToSignal { value -> Signal in let thumbnailData = value._0 if let data = thumbnailData, let image = UIImage(data: data) { @@ -273,7 +273,7 @@ func legacyWebSearchItem(account: Account, result: ChatContextResult) -> LegacyW return .complete() } } - originalSignal = chatMessagePhotoDatas(postbox: account.postbox, photoReference: .standalone(media: tmpImage), autoFetchFullSize: true) + originalSignal = chatMessagePhotoDatas(postbox: account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage), autoFetchFullSize: true) |> mapToSignal { value -> Signal in let thumbnailData = value._0 let fullSizeData = value._1 diff --git a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift index 0e72357fdc..cf0a43089e 100644 --- a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift @@ -38,11 +38,11 @@ struct WebSearchGalleryEntry: Equatable { case let .externalReference(externalReference): if let content = externalReference.content, externalReference.type == "gif", let thumbnailResource = externalReference.thumbnail?.resource, let dimensions = content.dimensions { let fileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: EngineMedia.Id(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: content.resource, previewRepresentations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: dimensions, flags: [])])) - return WebSearchVideoGalleryItem(context: context, presentationData: presentationData, index: self.index, result: self.result, content: NativeVideoContent(id: .contextResult(self.result.queryId, self.result.id), fileReference: fileReference, loopVideo: true, enableSound: false, fetchAutomatically: true), controllerInteraction: controllerInteraction) + return WebSearchVideoGalleryItem(context: context, presentationData: presentationData, index: self.index, result: self.result, content: NativeVideoContent(id: .contextResult(self.result.queryId, self.result.id), userLocation: .other, fileReference: fileReference, loopVideo: true, enableSound: false, fetchAutomatically: true), controllerInteraction: controllerInteraction) } case let .internalReference(internalReference): if let file = internalReference.file { - return WebSearchVideoGalleryItem(context: context, presentationData: presentationData, index: self.index, result: self.result, content: NativeVideoContent(id: .contextResult(self.result.queryId, self.result.id), fileReference: .standalone(media: file), loopVideo: true, enableSound: false, fetchAutomatically: true), controllerInteraction: controllerInteraction) + return WebSearchVideoGalleryItem(context: context, presentationData: presentationData, index: self.index, result: self.result, content: NativeVideoContent(id: .contextResult(self.result.queryId, self.result.id), userLocation: .other, fileReference: .standalone(media: file), loopVideo: true, enableSound: false, fetchAutomatically: true), controllerInteraction: controllerInteraction) } } preconditionFailure() diff --git a/submodules/WebSearchUI/Sources/WebSearchItem.swift b/submodules/WebSearchUI/Sources/WebSearchItem.swift index a789bd2a50..21d7506613 100644 --- a/submodules/WebSearchUI/Sources/WebSearchItem.swift +++ b/submodules/WebSearchUI/Sources/WebSearchItem.swift @@ -137,7 +137,7 @@ final class WebSearchItemNode: GridItemNode { } if !representations.isEmpty { let tmpImage = TelegramMediaImage(imageId: EngineMedia.Id(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: []) - updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage)) + updateImageSignal = mediaGridMessagePhoto(account: item.account, userLocation: .other, photoReference: .standalone(media: tmpImage)) } else { updateImageSignal = .complete() } diff --git a/submodules/WebUI/Sources/WebAppAlertContentNode.swift b/submodules/WebUI/Sources/WebAppAlertContentNode.swift index 244e63734f..d408b8f675 100644 --- a/submodules/WebUI/Sources/WebAppAlertContentNode.swift +++ b/submodules/WebUI/Sources/WebAppAlertContentNode.swift @@ -128,7 +128,7 @@ private final class WebAppAlertContentNode: AlertContentNode { self.updateTheme(theme) if let peerIcon = self.peerIcon { - let _ = freeMediaFileInteractiveFetched(account: account, fileReference: .standalone(media: peerIcon)).start() + let _ = freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: peerIcon)).start() self.iconDisposable = (svgIconImageFile(account: account, fileReference: .standalone(media: peerIcon)) |> deliverOnMainQueue).start(next: { [weak self] transform in if let strongSelf = self { diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 631fbb1c85..47d8184373 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -308,7 +308,7 @@ public final class WebAppController: ViewController, AttachmentContainable { } if let fileReference = fileReference { - let _ = freeMediaFileInteractiveFetched(account: strongSelf.context.account, fileReference: fileReference).start() + let _ = freeMediaFileInteractiveFetched(account: strongSelf.context.account, userLocation: .other, fileReference: fileReference).start() } strongSelf.iconDisposable = (svgIconImageFile(account: strongSelf.context.account, fileReference: fileReference, stickToTop: isPlaceholder) |> deliverOnMainQueue).start(next: { [weak self] transform in @@ -694,7 +694,7 @@ public final class WebAppController: ViewController, AttachmentContainable { } switch result { case let .instantView(webPage, anchor): - let controller = InstantPageController(context: strongSelf.context, webPage: webPage, sourcePeerType: .otherPrivate, anchor: anchor) + let controller = InstantPageController(context: strongSelf.context, webPage: webPage, sourceLocation: InstantPageSourceLocation(userLocation: .other, peerType: .otherPrivate), anchor: anchor) strongSelf.controller?.getNavigationController()?.pushViewController(controller) default: strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})