Commit graph

30405 commits

Author SHA1 Message Date
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
973c232c21 docs: implementation plan for flush InstantPage V2 block media
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:14:26 +02:00
isaac
9dc990d5d6 docs: spec for flush un-rounded InstantPage V2 block media
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:02:52 +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
isaac
83297bec0e Re-apply dynamic watch bundle id
Re-applies commit 1120b9084e (reverted in ef2c1d47cc during install
debugging). The install failure was proven to be the oversized watch
binary (fixed by DEAD_CODE_STRIPPING), not the bundle-id mechanism — which
was verified to produce a byte-identical artifact for ph.telegra.Telegraph.

xcodebuild bakes PRODUCT_BUNDLE_IDENTIFIER=<host>.watchkitapp and the watch
Info.plist derives WKCompanionAppBundleIdentifier via
$(PRODUCT_BUNDLE_IDENTIFIER:base), so the embedded watch app is correct for
any host (ph.telegra.Telegraph and org.telegram.TelegramInternal/enterprise)
with no post-build plist patching.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 18:07:34 +02:00
isaac
62d707b3b9 Merge branch 'watch2' 2026-06-01 18:01:00 +02:00
isaac
1872832e28 Improve InstantPage V2 layout: true font-height line boxes + code-block style
- layoutTextItem now sizes a text item to the true font line height (A + D)
  instead of the cap box: the line stack starts at lineBoxTopInset (the
  ascender headroom, max(0, fontAscent - fontLineHeight)) and the returned
  height is padded by the last line's descender. Inter-line advance is
  unchanged and per-line frames stay the cap box, so the baseline draw,
  decorations, reveal mask, and inline attachments translate consistently;
  the page grows.
- Size inline custom emoji to ~the font line height
  (font.ascender - font.descender + 4*pointSize/17) so they fit the taller
  line box instead of overflowing it; the line is not inflated.
- Add a dedicated code-block text style for rich messages (monospace font +
  codeBlock theme attribute) threaded through the rich-data bubble and send
  preview; unify the bubble code-block/separator colors.
- Adjust inter-block spacings and assorted V2 layout/divider details.
- Document the true-font-height box and emoji sizing in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 17:33:01 +02:00
isaac
7e531ca57b temp 2026-06-01 17:23:05 +02:00
isaac
bf2f6eb560 Improve instant view v2 layout 2026-06-01 17:22:29 +02:00
isaac
5403ffa8b0 Update tgwatch 2026-06-01 15:00:17 +02:00
isaac
e0899a01d5 Adjust spacings 2026-06-01 14:59:55 +02:00
isaac
18d124ab17 InstantPage V2: text items measure true font height (A + D)
Shift the line stack down by the ascender headroom (A - L, as
`lineBoxTopInset` to avoid colliding with the existing formula-bleed
`topInset` local) and pad the returned height by the last line's
descender (D), so a single-line V2 text item is a true ascent/descent
line box measuring exactly A + D instead of the cap box A - L. Inter-line
advance unchanged; formulas still inflate via lineAscent/extraDescent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 02:20:10 +02:00
isaac
758e596bf9 InstantPage: add code-block text style for rich messages
Local in-progress work (committed at the author's request as a checkpoint
before unrelated true-font-height work lands on top): introduces a
dedicated `codeBlock` InstantPage font/text style (.monospace / .codeBlock
font cases + monospace font resolution), adds a `codeBlock` field to the
InstantPage text-attributes theme and threads it through the rich-data
bubble and the send preview, and unifies the rich-bubble code-block
background/secondary-control colors.
2026-06-01 02:14:59 +02:00
isaac
5893b574a8 Add implementation plan: V2 text items as true font-height line boxes
Task 1: 3-line metric change in layoutTextItem (topInset shift + descender
pad). Task 2: re-tune the streaming chat-bubble bottom inset (the now-
contained descender makes the +6.0 hack partly redundant). Task 3: broad
visual verification of the remaining consumers (decorations, reveal mask,
lists, blockquotes, tables, title) with one gated table-inset fix. Task 4:
spec acceptance checklist. Verification model adapted to this repo: full
Bazel build + simulator visual checks (no unit tests exist).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 02:07:03 +02:00
isaac
625aac9294 Add design spec: V2 text items as true font-height line boxes
Approach 2 (true proper line box): shift the line stack down by the
ascender headroom (exact A - L, not pixel-snapped) and pad the returned
height by the last line's descender, so a single-line V2 text item
measures exactly the true font height (A + D) instead of the cap box
(A - D). Inter-line advance unchanged; formulas still inflate.
Documents the affected height/frame consumers (chat-bubble height +
status node, streaming clip, table cells, title centering, reveal cost)
and the verification plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 01:59:38 +02:00
isaac
9205fb2303 Fix inline emoji/image line-height inflation in InstantPage V2
The V2 line-breaker used `lineAscent` as both the line height and the
baseline offset, then inflated it to each inline emoji/image's full visual
size and bottom-aligned the attachment on that inflated baseline. A 24pt
emoji on a ~17pt line therefore doubled the line height and shoved the
text baseline (and all text on the line) down.

Stop inflating the line for emoji/images (only formulas, which carry their
own metrics, still grow it) and center each attachment on the font line
box at `baselineY - fontLineHeight/2 - size/2`, matching V1
`layoutTextItemWithString` and the chat `InteractiveTextComponent`. The
attachment now bleeds symmetrically instead of moving the baseline.
`extraDescent` absorbs tall-attachment bottom overflow so the next line is
not overlapped, and the streaming-reveal `characterRect` is centered in
lockstep so the reveal mask tracks the cell (reveal cost stays width-only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:28:05 +02:00
isaac
a3492c0cb0 Update tgwatch 2026-05-31 18:13:57 +02:00
isaac
750911ce3c Merge commit '14ade58f34' 2026-05-31 18:05:01 +02:00
isaac
471ae08219 Merge commit 'e2de53ea17' 2026-05-31 18:04:21 +02:00
isaac
14ade58f34 Merge commit 'e2de53ea17' 2026-05-31 18:00:47 +02:00
isaac
6bcf266118 Remove stop button 2026-05-31 18:00:38 +02:00
isaac
ef2c1d47cc Revert "Update tgwatch signing"
Revert the universal/dynamic watch bundle id change (commit 1120b9084e)
back to the static 0682 shape, for install testing.

This reverts the PRODUCT_BUNDLE_IDENTIFIER override + $(...:base) companion-id
derivation; the watch app again bakes the hardcoded ph.telegra.Telegraph.watchkitapp
and literal WKCompanionAppBundleIdentifier=ph.telegra.Telegraph.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:58:30 +02:00
isaac
3ed8c926a8 Custom emoji in markdown rich messages (send + round-trip)
Parse custom emoji into RichText.textCustomEmoji when sending markdown
rich messages, and round-trip them through edit, copy, and paste using a
shared tg://emoji?id=<fileId> markdown-link marker.

- Send: rewrite each customEmoji input attribute into a
  [<alt>](tg://emoji?id=<fileId>) marker before the CommonMark parse, then
  intercept the marker URL afterward to emit .textCustomEmoji. Only rich
  messages are affected; a custom emoji alone stays on the entity path.
- Reverse: InstantPageToMarkdown (whole-message copy + edit reconstruction)
  and InstantPageMultiTextAdapter (selection copy) emit the marker;
  edit-load and chat paste reattach it as a live customEmoji attribute.
- Marker helpers shared in TextFormat/CustomEmojiMarkdownMarker.swift.
- Rich sends now pass inlineStickers so recipients can fetch the files.

Follow-up to verify at runtime: recipient rendering goes out with
Api.InputRichMessage.documents: nil; if recipients see only the fallback
glyph, populate documents: in apiInputRichMessage().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:51:37 +02:00
Ilya Laktyushin
e2de53ea17 Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios 2026-05-31 17:35:39 +02:00
Ilya Laktyushin
622f9d970a Various fixes 2026-05-31 17:35:32 +02:00
isaac
6408175725 InstantPage V2 thinking block: text-item sizing, overhang, inline emoji/images
Make the thinking block render consistently with a normal text item:

- Size the `.thinking` item frame text-width at the page inset
  (`(horizontalInset, 0, textWidth, height)`), identical to a `.text`
  item, instead of a full-bleed `(0, 0, boundingWidth, height)` box, by
  laying the text out flush and moving the inset onto the block frame.
  The shimmer (sized to `item.frame.size`) now hugs the text.

- Size the shimmer + its gradient mask to the clipping-inset-expanded
  frame (shifted `-inset`) so the mask no longer crops glyph ascenders,
  descenders and the last line's underline, mirroring how a `.text`
  view's frame is inset-expanded.

- Visit the thinking block's shimmer-wrapped inner text view in
  updateInlineEmoji / updateInlineImages so its inline custom emoji and
  images get layers created, positioned and revealed. They were skipped
  because the page only iterated top-level InstantPageV2TextView items.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:49:33 +02:00
isaac
1120b9084e Update tgwatch signing 2026-05-31 15:34:43 +02:00
isaac
d4736fe59f Revert tgwatch signing 2026-05-31 15:04:50 +02:00
isaac
f6dc52c533 Update layout 2026-05-30 23:27:26 +02:00
isaac
3525bcacb2 Add watch profile guard 2026-05-30 22:16:10 +02:00
isaac
dbd53522be Merge commit '98d148e08d' 2026-05-30 18:49:56 +02:00
isaac
eb1b918a77 InstantPage V2 table: cell layout polish (insets, text category, border width)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:47:04 +02:00
isaac
3d9fbdec3c InstantPage V2 table: rounded corners and corner-cell fill rounding
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:47:04 +02:00
isaac
79bcc7bc34 InstantPage V2 table: flush frame, inset borders
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:47:03 +02:00
isaac
e8de87dc7b InstantPage V2: render server-sent thinking blocks
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:47:03 +02:00
Ilya Laktyushin
98d148e08d Various fixes 2026-05-29 16:46:38 +02:00
isaac
484b66f28c Add implementation plan: InstantPage V2 thinking-block + cross-update view reuse
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 16:36:40 +02:00
isaac
a50f40476d Add design spec: InstantPage V2 thinking-block rendering + cross-update view reuse
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 16:28:37 +02:00
isaac
79ee96306b Update tgwatch 2026-05-29 16:08:23 +02:00
isaac
354e1c7a66 Implement InstantPageBlock.thinking (pageBlockThinking) parsing & serialization
Add a first-class InstantPageBlock.thinking(RichText) case mirroring .kicker:
- enum case + InstantPageBlockType.thinking = 30; Postbox coding & equality
- FlatBuffers InstantPageBlock_Thinking schema (appended last) + Swift codecs
- API parse at InstantPage.swift; output-only on send (apiInputBlock returns nil)
- no-op stubs in the two exhaustive switches (preview text, V2 layout)

Rendering is out of scope. Verified by a full Bazel build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 16:07:09 +02:00
isaac
bd8886b0f0 Merge commit '4b2a826682' 2026-05-29 15:47:41 +02:00
isaac
5950bbe8a1 Fix code 2026-05-29 15:47:37 +02:00
isaac
1d8931b334 Render markdown rich-text preview in send-message context screen
When the user long-presses Send in the main chat and the composed text passes the
same rich-markdown gate used at send time (richMarkdownAttributeIfNeeded), the
send-options preview bubble renders the message as rich InstantPage content,
crossfading from the raw text as the menu animates in. Plain text and custom chat
contents / edit previews are unchanged.

ChatSendMessageActionUI cannot depend on InstantPageUI (it closes a dependency
cycle via LocationUI -> AttachmentUI -> ... -> ChatTextInputActionButtonsNode), so
the rich view is built in TelegramUI (ChatSendMessageRichTextPreview, wrapping
InstantPageV2View + the outgoing message theme) and injected into the screen via a
new ChatSendMessageContextScreenRichTextPreview protocol, mirroring the existing
media-preview pattern. The main-chat send call site classifies the compose text
and injects the preview; MessageItemView lays it out within the send-button-bounded
bubble envelope and crossfades between the raw text and the rich layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 15:46:16 +02:00
isaac
471d11df16 Copy rich messages as markdown (whole message + partial selection)
Rich messages (RichTextMessageAttribute, text == "") are copyable as
markdown two ways: the context-menu Copy action copies the whole
message, and a text selection inside the rich-data bubble copies just
the selected range. Both reconstruct markdown mirroring the edit
round-trip (markdownStringFromInstantPage).

Implements the full RichText entity case set
(mention/hashtag/cashtag/bot-command/bank-card/auto url/email/phone) with
tap interaction, the InstantPage -> markdown inverse converter and edit
round-trip, markdown-context stamping during V2 layout
(InstantPageMarkdownBlockContext: heading level, list/code/table/quote
depth), partial-selection markdown emission
(InstantPageMultiTextAdapter.markdownForRange), and numerous converter
edge-case fixes (tables, links, fenced code, blockquote line coalescing,
compact nested >> markers).

CLAUDE.md documents the feature; the spec/plan scratch docs generated
during development are not committed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 13:52:47 +02:00
Ilya Laktyushin
4b2a826682 Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios 2026-05-29 10:01:53 +02:00
Ilya Laktyushin
e0f4655cc5 Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios 2026-05-29 09:24:16 +02:00
isaac
65eac2fa94 Update tgwatch 2026-05-29 02:03:31 +02:00
isaac
befacaa5fe InstantPage: distinct per-level heading sizes 2026-05-29 01:54:03 +02:00
isaac
28763bb92d InstantPage blockQuote: nested-blocks payload
Upgrade InstantPageBlock.blockQuote from (text, caption) to
(blocks: [InstantPageBlock], caption). Legacy inbound shapes (API
pageBlockBlockquote, Postbox "t", FlatBuffers text) lift into
[.paragraph(text)]; outbound stays on the legacy wire constructor for
empty/single-paragraph quotes and uses pageBlockBlockquoteBlocks
otherwise. V1/V2 renderers recurse into child blocks with a fixed 10pt
inter-child gap; markdown forward/reverse, entity-expressibility, and
preview text updated. pullQuote is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 01:00:47 +02:00
isaac
ef7d582849 Update consumers for regenerated TL API
Regenerated TelegramApi sources and updated the affected consumers:
- InstantPage ordered-list encode: inputPageBlockOrderedList -> pageBlockOrderedList
- ChatContextResult: handle new constructor (exhaustive switch)
- JoinChannel/JoinLink: chatInviteJoinResultWebView now (botId, webview, users)
- WebUI chat-context-result preview consumers
2026-05-29 00:55:12 +02:00