Telegram-iOS/submodules/InstantPageUI/Sources/InstantPageImageItem.swift
isaac e2da230af6 InstantPage V2: media rendering (image / video / map / cover)
Design and plan, then the implementation: extract a shared
openInstantPageMedia helper for V1+V2 reuse, add typed media item
cases + allMedias() helper, introduce InstantPageV2RenderContext and
thread it through the view tree, add four media wrapper views, route
layout dispatch through typed media items, let the chat bubble build
the render context so real media renders, wire gallery tap routing,
cache V2View by message id + stableVersion, add stable-id identity +
per-class update(item:theme:), reuse item views on re-layouts via
stable-id harvest, preserve TextView clipping inset on reuse, and let
the use site control media-reference construction.
2026-05-20 00:33:28 +08:00

86 lines
3.2 KiB
Swift

import Foundation
import UIKit
import TelegramCore
import AsyncDisplayKit
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
import ContextUI
public protocol InstantPageImageAttribute {
}
public struct InstantPageMapAttribute: InstantPageImageAttribute {
public let zoom: Int32
public let dimensions: CGSize
public init(zoom: Int32, dimensions: CGSize) {
self.zoom = zoom
self.dimensions = dimensions
}
}
public final class InstantPageImageItem: InstantPageItem {
public var frame: CGRect
let webPage: TelegramMediaWebpage
public let media: InstantPageMedia
let attributes: [InstantPageImageAttribute]
public var medias: [InstantPageMedia] {
return [self.media]
}
public let interactive: Bool
let roundCorners: Bool
let fit: Bool
public let wantsNode: Bool = true
public let separatesTiles: Bool = false
init(frame: CGRect, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute] = [], interactive: Bool, roundCorners: Bool, fit: Bool) {
self.frame = frame
self.webPage = webPage
self.media = media
self.attributes = attributes
self.interactive = interactive
self.roundCorners = roundCorners
self.fit = fit
}
public 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]?, getPreloadedResource: @escaping (String) -> Data?) -> 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, getPreloadedResource: getPreloadedResource)
}
public func matchesAnchor(_ anchor: String) -> Bool {
return false
}
public func matchesNode(_ node: InstantPageNode) -> Bool {
if let node = node as? InstantPageImageNode {
return instantPageMediaMatchesNodeIdentity(node.media, self.media)
} else {
return false
}
}
public func distanceThresholdGroup() -> Int? {
return 1
}
public func distanceThresholdWithGroupCount(_ count: Int) -> CGFloat {
if count > 3 {
return 400.0
} else {
return CGFloat.greatestFiniteMagnitude
}
}
public func drawInTile(context: CGContext) {
}
public func linkSelectionRects(at point: CGPoint) -> [CGRect] {
return []
}
}