Improve instant view v2 layout

This commit is contained in:
isaac 2026-06-01 17:22:29 +02:00
parent e0899a01d5
commit bf2f6eb560
5 changed files with 25 additions and 19 deletions

View file

@ -16,7 +16,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?, fi
return 0.0
case (.divider, _), (_, .divider):
if fitToWidth {
return 20.0
return 21.0
} else {
return 25.0
}
@ -82,7 +82,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?, fi
return 31.0
case (.preformatted, _), (_, .preformatted):
if fitToWidth {
return 5.0
return 12.0
} else {
return 19.0
}
@ -113,11 +113,11 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?, fi
case .topLevel:
switch lower {
case .heading:
return 13.0
case .paragraph:
return 0.0
default:
return 6.0
case .table:
return 10.0
default:
return 5.0
}
case .cell:
return 0.0
@ -133,8 +133,8 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?, fi
case .topLevel:
if case .relatedArticles = upper {
return 0.0
} else if case .paragraph = upper {
return 0.0
} else if case .thinking = upper {
return 2.0
} else {
if fitToWidth {
return 5.0

View file

@ -960,7 +960,11 @@ func attributedStringForRichText(_ text: RichText, styleStack: InstantPageTextSt
}
let attributes = styleStack.textAttributes()
let font = (attributes[NSAttributedString.Key.font] as? UIFont) ?? UIFont.systemFont(ofSize: 17.0)
let itemSize = font.pointSize * 24.0 / 17.0
// Size the inline emoji to the font's line height (A + D) plus a 4pt bump at the 17pt
// body font (scaled proportionally). Must match the V2 layout's emoji cell size
// (InstantPageV2Layout.swift). The run delegate still reports the font's own
// ascent/descent (below), so the line height is unchanged only the emoji width changes.
let itemSize = font.ascender - font.descender + 4.0 * font.pointSize / 17.0
let extentBuffer = UnsafeMutablePointer<RunStruct>.allocate(capacity: 1)
extentBuffer.initialize(to: RunStruct(ascent: font.ascender, descent: font.descender, width: itemSize))
var callbacks = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { pointer in

View file

@ -440,7 +440,7 @@ public func lastTextLineFrame(in layout: InstantPageV2Layout) -> CGRect? {
/// Also returns `trailingBottomPadding`: the renderer draws the baseline at the line frame's maxY,
/// so the visible text of a plain line sits ~5pt below it. A status that *trails on the line* should
/// anchor at `maxY + trailingBottomPadding` to align with where the text actually renders. The pad
/// is 0 when the line is taller than its font line height (an inline animated emoji, ~pointSize·24/17,
/// is 0 when the line is taller than its font line height (a tall inline attachment, e.g. a formula,
/// already pushes maxY down to the right spot). Callers should NOT apply the pad when the status
/// wraps onto its own line below the text there it should sit at the bare maxY.
public func lastTextLineFrameIfLastItemIsText(in layout: InstantPageV2Layout) -> (frame: CGRect, trailingBottomPadding: CGFloat)? {
@ -1899,17 +1899,14 @@ private func layoutDivider(
boundingWidth: CGFloat,
context: LayoutContext
) -> [InstantPageV2LaidOutItem] {
// Geometry matches V1 InstantPageLayout.swift lines 361363:
// lineWidth = floor(boundingWidth / 2.0), x = floor((boundingWidth - lineWidth) / 2.0), h = 1pt.
// Color matches V1: theme.textCategories.caption.color.
let lineWidth = floor(boundingWidth / 2.0)
let frame = CGRect(
x: floor((boundingWidth - lineWidth) / 2.0),
y: 0.0,
width: lineWidth,
height: 1.0
height: UIScreenPixel
)
return [.divider(InstantPageV2DividerItem(frame: frame, color: context.theme.textCategories.caption.color))]
return [.divider(InstantPageV2DividerItem(frame: frame, color: context.theme.separatorColor))]
}
// MARK: - Code block layout (ported from V1 InstantPageLayout.swift lines 329351)
@ -2848,7 +2845,12 @@ func layoutTextItem(
} else if let emoji = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
let xOffset = CTLineGetOffsetForStringIndex(line, range.location, nil)
let font = (attributes[NSAttributedString.Key.font] as? UIFont) ?? UIFont.systemFont(ofSize: 17.0)
let itemSize = font.pointSize * 24.0 / 17.0
// Size the inline emoji to the font's line height (A + D = the true
// line-box height) plus a 4pt bump at the 17pt body font (scaled
// proportionally) so it reads a touch larger than the bare line box.
// The line is NOT inflated (lineAscent stays fontLineHeight). Must match
// the run-delegate width in attributedStringForRichText (InstantPageTextItem.swift).
let itemSize = font.ascender - font.descender + 4.0 * font.pointSize / 17.0
pendingEmoji.append(PendingV2EmojiAttachment(xOffset: xOffset, range: range, emoji: emoji, size: itemSize))
}
}
@ -2914,7 +2916,7 @@ func layoutTextItem(
extraDescent = max(0.0, lineDescent - baselineToNextTopSlack)
// A centered attachment taller than the line bleeds below the baseline; grow the
// descent so the following line isn't overlapped (mirrors V1's extraDescent handling).
// Emoji at the default 24/17 ratio stay within the line slack and contribute nothing.
// Emoji sized to the font line height (A + D) fit the line box, so they contribute nothing.
for imageItem in lineImageItems {
extraDescent = max(extraDescent, imageItem.frame.maxY - (baselineY + baselineToNextTopSlack))
}

View file

@ -303,7 +303,7 @@ public class ChatMessageRichDataBubbleContentNode: ChatMessageBubbleContentNode
controlColor: messageTheme.accentControlColor,
imageTintColor: nil,
overlayPanelColor: isDark ? UIColor(white: 0.0, alpha: 0.13) : UIColor(white: 1.0, alpha: 0.13),
separatorColor: isIncoming ? UIColor(white: 0.0, alpha: 0.25): messageTheme.accentControlColor.withMultipliedAlpha(0.25),
separatorColor: messageTheme.secondaryTextColor.mixedWith(mainColor.withMultipliedAlpha(0.2), alpha: 0.3),
secondaryControlColor: messageTheme.secondaryTextColor.mixedWith(mainColor.withMultipliedAlpha(0.2), alpha: 0.3)
)

View file

@ -120,7 +120,7 @@ final class ChatSendMessageRichTextPreview: ChatSendMessageContextScreenRichText
tableHeaderColor: messageTheme.accentControlColor.withMultipliedAlpha(0.1),
controlColor: messageTheme.accentControlColor,
imageTintColor: nil,
overlayPanelColor: isDark ? UIColor(white: 0.0, alpha: 0.13) : UIColor(white: 1.0, alpha: 0.13),
overlayPanelColor: messageTheme.accentControlColor.withMultipliedAlpha(0.25),
separatorColor: messageTheme.accentControlColor.withMultipliedAlpha(0.25),
secondaryControlColor: messageTheme.secondaryTextColor
)