Telegram-iOS/submodules/InstantPageUI
isaac 1d82735d61 InstantPage V2: render inline RichText images
Renders `RichText.image(id:, dimensions:)` runs as real fetched images
inside `ChatMessageRichDataBubbleContentNode` / `InstantPageV2View`,
replacing the gray `InstantPageV2MediaPlaceholderView`. Source is
whatever populates `instantPage.media[id]` (server-pushed webpage
InstantPages); the markdown converter is unchanged
(`markdownImageParsingEnabled` stays false).

Architecture mirrors inline custom emoji: inline images are NOT
top-level `InstantPageV2LaidOutItem`s. `InstantPageV2View` walks each
text view's `line.imageItems`, resolves each MediaId against
`layout.media`, and creates `InstantPageV2InlineImageView` children
inside a new `imageContainerView` on each `InstantPageV2TextView`
(sibling of `renderContainer`, above the reveal mask, below
`emojiContainerView`).

Streaming reveal participation: image cells contribute their full
width to the per-line character rects (mirrors emoji), so the cost map
charges the cursor by the image's width when crossing it. When the
cursor crosses the cell, `updateImageReveal` pops the view in
(opacity 0→1 + scale 0.1→1.0 over 0.2s ease-out), matching
`updateEmojiReveal` exactly. `applyReveal` calls both alongside each
other.

Non-interactive (V1 parity): `isUserInteractionEnabled = false` lets
URL-wrapping `RichText.url(text: .image(...))` route taps through to
the underlying text view's URL handler.

Key files:
- New `InstantPageV2InlineImageView.swift`: lightweight
  `TransformImageNode`-backed view. Picks the fetch signal by
  EngineMedia kind (.image → chatMessagePhoto; image-mime .file →
  instantPageImageFile; video .file → chatMessageVideo single frame).
  `MetaDisposable` cancels fetches on dealloc.
- `InstantPageV2Layout.swift`: `media`/`webpage` fields on the layout
  struct; image cells contribute to char rects; the gray-placeholder
  branch in `layoutTextItem` is removed; the dead `media`/`webpage`
  params on `layoutTextItem` are dropped along with their 13 call
  sites.
- `InstantPageRenderer.swift`: `imageContainerView` on text view
  (sibling of `renderContainer`, between it and `emojiContainerView`);
  `InlineImageKey` + `InstantPageInlineImageData` types;
  `updateInlineImages()` + `updateImageReveal()` on
  `InstantPageV2View`; wired into `update(layout:theme:animation:)`.
- `InstantPageV2RevealCost.swift`: `applyReveal` calls
  `updateImageReveal` next to `updateEmojiReveal` in both the
  clear-path branch and the entry-walking branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 14:21:25 +02:00
..
Sources InstantPage V2: render inline RichText images 2026-05-28 14:21:25 +02:00
BUILD RichText.textSpoiler: dust overlay + tap-to-reveal in rich-data bubbles 2026-05-23 22:12:47 +04:00