Commit graph

5 commits

Author SHA1 Message Date
isaac
f6da30da70 InstantPage V2: audio/music rendering, playback, and file-bubble styling
Render and play InstantPageBlock.audio in the InstantPage V2 renderer
(rich-data message bubbles + the rich send preview), where audio was
previously an inert grey placeholder.

- New InstantPageV2AudioContentNode replicates the standard music message
  bubble (ChatMessageInteractiveFileNode's music layout): a SemanticStatusNode
  control (album art via playerAlbumArt + play/pause) with a download/progress
  overlay, title + "duration · performer" lines, exact fonts/colors from
  theme.chat.message.{incoming|outgoing}. Tap is driven by a
  UITapGestureRecognizer (ASControl .touchUpInside is cancelled by the chat
  ListView's gesture system). V1's InstantPageAudioNode is unchanged.
- Playback runs on InstantPageMediaPlaylist with a discriminated, message-scoped
  InstantPageMediaPlaylistId (.instantPage / .richMessage) so concurrent
  rich-message audio bubbles don't collide; the big control's play/pause comes
  from filteredPlaylistState, the overlay's download/progress from
  messageMediaFileStatus, and fetch goes through the fetch manager.
- Rich-message audio fetches via a MessageReference (threaded through the V2
  render context) instead of the synthesized webpage; FetchedMediaResource's
  .message revalidation arm now also searches RichTextMessageAttribute instant
  pages, so a stale instant-page audio/image reference can recover. Corrected a
  dormant inverted InstantPagePlaylistLocation.isEqual.
- New .mediaAudio laid-out item + layout/reveal-cost arms; the audio block lays
  out full-width at the file node's music normHeight.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 17:44:45 +02:00
isaac
ab68a1af82 InstantPage V2: render collage & slideshow blocks
Port V1's collage and slideshow InstantPage blocks into the V2 renderer
(previously grey-box placeholders).

- Collage: layoutCollage computes the mosaic (MosaicLayout, the grouped-message
  engine) over inner image/video sizes and flattens it into existing top-level
  .mediaImage/.mediaVideo items + a caption, so gallery / reveal-cost / registry
  / hidden-media all handle the cells with no collage-specific code. Right-edge
  cells bleed 4pt for the bubble's rounded clip.
- Slideshow: a new .slideshow laid-out item + InstantPageV2SlideshowView, an
  eager paged carousel (UIScrollView + PageControlNode) of InstantPageImageNode
  pages, wired through frame/offsetBy/collectMedias/stableId/reuse/makeItemView
  and the reveal-cost non-text list.
- Gallery transitions generalized onto InstantPageItemView via
  instantPageTransitionNode(for:)/instantPageUpdateHiddenMedia(_:) (default
  nil/no-op; explicit per-class witnesses on the 4 static media views, the
  slideshow forwards to its live pages) so the multi-media slideshow can
  participate alongside single-media views.

Docs: document both in docs/instantpage-richtext.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:50:40 +02:00
isaac
071799368d InstantPage V2: fall back to 600x300 for zero-dimension map blocks
AI/server-sent .map blocks can arrive with dimensions == 0x0 (the wire
w/h are required Int32, but the sender may put 0; our parse and both
serializers preserve whatever arrives). A zero naturalSize.height hit
instantPageV2MediaFrame's else branch and returned a height-0 frame:
the map collapsed to no space, the caption slid up into it, and the V1
node's pin floated over the caption. A zero-sized MapSnapshotMediaResource
would also make MKMapSnapshotter render nothing.

Substitute PixelDimensions(600, 300) (2:1) whenever width <= 0 ||
height <= 0, feeding effectiveDimensions to BOTH the layout naturalSize
AND the InstantPageMapAttribute so the snapshot resource is non-zero and
actually renders. Scoped to the V2 .map arm; V1 (real web articles)
always carries real dimensions and never trips this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:36:18 +02:00
isaac
9b1573e87e InstantPage V2: flush, un-rounded block media (except audio)
All block-media kinds except .audio now lay out edge-to-edge (0 inset) with
cornerRadius 0; the bubble's existing rounded containerNode clip rounds media at
the bubble edge. Small images keep natural size (not upscaled); captions stay
inset. Shared instantPageV2MediaFrame helper + flush flag on the two media
layout helpers. V1 unchanged. Invariants documented in docs/instantpage-richtext.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 00:32:24 +02:00
isaac
804c02743a docs: slim CLAUDE.md, extract rich-text/InstantPage notes
Remove stale data from CLAUDE.md and split out the large InstantPage V2 /
rich-text feature documentation into its own file.

- Drop two dead spec links (table inset/corner-radius design docs no longer
  exist), the orphaned debugRichText cleanup note (flag is read by nothing),
  and the stale "238 waves as of 2026-05-04" count.
- Remove the duplicated Postbox "Wave-selection guidance" and "facade
  inventory" subsections; both live in docs/superpowers/postbox-refactor-log.md
  and TelegramEngineResources.swift (pointer folded into the Historical record).
- Move the 13 InstantPage V2 / rich-text sections to
  docs/instantpage-richtext.md, leaving a brief pointer in CLAUDE.md.

CLAUDE.md: 507 -> 161 lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 20:33:41 +02:00