Implement the nine message-entity RichText cases (textMention,
textMentionName, textHashtag, textCashtag, textBotCommand, textBankCard,
textAutoUrl, textAutoEmail, textAutoPhone): model + Postbox coding,
FlatBuffers schema/codec, Api.RichText parsing/serialization (lossless),
InstantPage display attaching the matching TelegramTextAttributes keys, and
tap routing in the rich-data bubble mirroring ChatMessageTextBubbleContentNode.
mentionName display resolves via EnginePeer.Id (PeerId not in scope).
Also lets rich-data text selection reach a line's trailing edge and fixes
the date/status node positioning to match TextBubble.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add the RichText.textCustomEmoji(fileId:alt:) case end-to-end: model +
Postbox coding, FlatBuffers schema/codec, and Api.RichText
parsing/serialization (lossless), plus display in the InstantPage V2
renderer. The emoji renders as an InlineStickerItemLayer that participates
in the streaming reveal (pops in as the reveal cursor crosses it) and is
gated by the bubble's visibility rect, propagated recursively through the
nested V2 view tree. Also frees the CTRunDelegate extent buffers for the
image/formula/custom-emoji attachment arms and documents the feature in
CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Spec, plan, and full implementation of the AI-message streaming
animation in ChatMessageRichDataBubbleContentNode. Extracts
TextRevealController into a shared StreamingTextReveal submodule;
precomputes per-character rects in V2 layout (RTL-safe, glyph-ink
bounds); splits InstantPageV2TextView into render container + render
view with a reveal mask layer; implements mask + snippet pop-in
reveal; adds a per-text-view reveal cost map + applyReveal extension;
switches reveal cost to a width-based unit; sizes / clips the bubble
to the revealed prefix during streaming; aligns the Thinking… header
with TextBubble; floors table cell reveal cost at cell frame width;
includes layout closing pad in revealedContentSize; documents the
non-obvious invariants in CLAUDE.md.
Design and plan, then implementation: include the details title in
selectableTextItems, restore V2 text selection in the rich bubble,
drop the InstantPageMultiTextAdapter init parameter-name split, and
split LinkHighlightingNode modern-path groups on disjoint rects.
Also includes the IP V2 inline-formula baseline alignment design doc.
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.
Initial design, plan, scaffold, and the full incremental implementation
of InstantPage V2 used by ChatMessageRichDataBubbleContentNode: layout
data types and driver, shared text helpers, text view / divider /
anchor, lists, code blocks, block/pull quotes, media placeholders,
details (with recursion), tables, hit-test / selection / last-line
helpers, V1→V2 swap in the rich-data bubble, and post-swap fix-ups
(cache key, RTL paragraphs, list geometry, lazy pageView construction,
fitToWidth horizontal inset, V2View.update() no longer writes
self.frame).
Spec, plan, and implementation of the date / checks / reactions /
effects status node on ChatMessageRichDataBubbleContentNode. Hoists
layout work out of the inner closure and anchors the status frame top
at text maxY.
Smooth-pace reveal of incoming live typing drafts. Adds the design
doc, implementation plan, the EWMA inter-arrival → velocity-smoothed
cursor core, handling for text shrink / item loss, and debug logs.
Sweep 14 BUILD files whose modules no longer have any source file with
`import Postbox`. All targets are ChatMessage*BubbleContentNode subclasses
plus WallpaperPreviewMedia — modules whose Swift sources stopped importing
Postbox in earlier waves but whose BUILD deps were not cleaned up.
Pre-flight: for each `BUILD` containing `"//submodules/Postbox"`, verified
no source file under `<module>/Sources` matches `^import Postbox$`. 14
modules met the criterion.
Build: 15s warm-cache verify, 0 errors.
Modules:
- ChatMessageActionBubbleContentNode
- ChatMessageEventLogPreviousDescriptionContentNode
- ChatMessageEventLogPreviousLinkContentNode
- ChatMessageEventLogPreviousMessageContentNode
- ChatMessageFileBubbleContentNode
- ChatMessageGameBubbleContentNode
- ChatMessageInvoiceBubbleContentNode
- ChatMessageMapBubbleContentNode
- ChatMessageMediaBubbleContentNode
- ChatMessageProfilePhotoSuggestionContentNode
- ChatMessageStoryMentionContentNode
- ChatMessageWallpaperBubbleContentNode
- ChatMessageWebpageBubbleContentNode
- WallpaperPreviewMedia
Pre-wave attempt failure note: tried 5 source-side `import Postbox` drops
first (StatsMessageItem, StarsAvatarComponent, PeerListItemComponent,
WebAppMessagePreviewScreen, OpenChatMessage). All 5 hit hidden bare
`Media`/`Message`/`PeerStoryStats`/`areMediaArraysEqual` references that
the prior pre-flight regex missed. Reverted source edits; only the
risk-free BUILD-dep sweep survives in this commit.
Lesson: pre-flight regex MUST include bare Postbox protocols
`\bMedia\b`, `\bMessage\b`, `\bPeer\b`, plus the Postbox helper
`areMediaArraysEqual` and the `PeerStoryStats` type. The previous
identifier-typealias-only regex was insufficient.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migrate `cachedWallpaper(account: Account, ...)` in WallpaperCache.swift to
take `(engine: TelegramEngine, network: Network, ...)` instead of the umbrella
Account parameter. Body drops the local `let engine = TelegramEngine(account:)`
since engine is now a parameter; `account.network` is now `network`.
19 context-based callers (`account: context.account` /
`self.context.account` / `component.context.account`) update via perl
sweep to pass `engine: context.engine, network: context.account.network`.
3 internal-Account-typed callers (WallpaperResources.swift × 2,
ThemeUpdateManager.swift × 1) bridge with adhoc
`engine: TelegramEngine(account: account), network: account.network`
since they're inside functions that still take `account: Account` and have
heavier Postbox uses we can't migrate yet.
Drops `import Postbox` from WallpaperCache.swift since the only remaining
Postbox-ish identifier was `ValueBoxKey`, which swaps to `EngineDataBuffer`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds drag-handle text selection driven by TextSelectionNode. Exposes
attributedString and selection helpers on InstantPage text items, and
introduces a multi-text adapter aggregating items as a TextNodeProtocol.
Gates selection actions on reply-options and fixes highlight z-order.
Adds a base getAnchorRect on ChatMessageBubbleContentNode, the rich-bubble
override (including titleHeight in details recursion), bubble-item
forwarding to content nodes, ChatControllerInteraction.scrollToMessageIdWithAnchor,
and a scrollToAnchor that lands the anchor at the top of the content area /
its line. Threads anchor/scroll params through ChatController and related
call sites.
Adds ChatControllerInteraction dependency, link-progress state, URL tap
detection, press-highlight separation from in-flight URL shimmer, media-tap
routing through openMessage with explicit IV media subject, and gallery↔bubble
transition with hidden-media coordination. Stops re-appending to
currentLayoutItemsWithNodes across re-layouts. Drops a leftover MetalEngine
debug print as well.