mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
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>
This commit is contained in:
parent
ef7d582849
commit
28763bb92d
10 changed files with 233 additions and 62 deletions
|
|
@ -1116,8 +1116,14 @@ private func blockIsEntityExpressible(_ block: InstantPageBlock) -> Bool {
|
|||
return richTextIsEntityExpressible(text)
|
||||
case .preformatted(let text, _):
|
||||
return richTextIsEntityExpressible(text)
|
||||
case .blockQuote(let text, let caption):
|
||||
return isEmptyRichText(caption) && richTextIsEntityExpressible(text)
|
||||
case .blockQuote(let blocks, let caption):
|
||||
guard isEmptyRichText(caption) else { return false }
|
||||
return blocks.allSatisfy { child in
|
||||
if case let .paragraph(text) = child {
|
||||
return richTextIsEntityExpressible(text)
|
||||
}
|
||||
return false
|
||||
}
|
||||
case .anchor, .unsupported:
|
||||
return true
|
||||
case .divider:
|
||||
|
|
@ -1392,24 +1398,17 @@ private func markdownBlocks(from node: MarkdownIntentNode, context: MarkdownConv
|
|||
case .thematicBreak:
|
||||
return [.divider]
|
||||
case .blockQuote:
|
||||
var result: [InstantPageBlock] = []
|
||||
var childBlocks: [InstantPageBlock] = []
|
||||
for child in node.children {
|
||||
guard let childBlocks = markdownBlocks(from: child, context: context, depth: depth + 1) else {
|
||||
guard let parsed = markdownBlocks(from: child, context: context, depth: depth + 1) else {
|
||||
return nil
|
||||
}
|
||||
for childBlock in childBlocks {
|
||||
switch childBlock {
|
||||
case let .paragraph(text):
|
||||
result.append(.blockQuote(text: text, caption: .empty))
|
||||
default:
|
||||
let plainText = markdownPlainText(from: childBlock, depth: depth + 1)
|
||||
if !plainText.isEmpty {
|
||||
result.append(.blockQuote(text: .plain(plainText), caption: .empty))
|
||||
}
|
||||
}
|
||||
}
|
||||
childBlocks.append(contentsOf: parsed)
|
||||
}
|
||||
return result
|
||||
guard !childBlocks.isEmpty else {
|
||||
return []
|
||||
}
|
||||
return [.blockQuote(blocks: childBlocks, caption: .empty)]
|
||||
case .orderedList:
|
||||
guard let items = markdownListItems(from: node.children, ordered: true, context: context, depth: depth + 1) else {
|
||||
return nil
|
||||
|
|
@ -2213,8 +2212,9 @@ private func markdownPlainText(from block: InstantPageBlock, depth: Int = 0) ->
|
|||
return text.plainText
|
||||
case let .footer(text):
|
||||
return text.plainText
|
||||
case let .blockQuote(text, caption):
|
||||
return text.plainText.isEmpty ? caption.plainText : text.plainText
|
||||
case let .blockQuote(blocks, caption):
|
||||
let blocksText = blocks.map { markdownPlainText(from: $0, depth: depth + 1) }.joined(separator: "\n")
|
||||
return blocksText.isEmpty ? caption.plainText : blocksText
|
||||
case let .pullQuote(text, caption):
|
||||
return text.plainText.isEmpty ? caption.plainText : text.plainText
|
||||
case let .kicker(text):
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ private func parsePageBlocks(_ input: [Any], _ url: String, _ media: inout [Engi
|
|||
case "pre":
|
||||
result.append(.preformatted(text: .fixed(trim(parseRichText(item, &media))), language: nil))
|
||||
case "blockquote":
|
||||
result.append(.blockQuote(text: .italic(trim(parseRichText(item, &media))), caption: .empty))
|
||||
result.append(.blockQuote(blocks: [.paragraph(.italic(trim(parseRichText(item, &media))))], caption: .empty))
|
||||
case "img":
|
||||
if let image = parseImage(item, &media) {
|
||||
result.append(image)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ private func markdownString(from block: InstantPageBlock) -> String? {
|
|||
case let .preformatted(text, language):
|
||||
let language = language ?? ""
|
||||
return "```\(language)\n\(markdownInline(from: text))\n```"
|
||||
case let .blockQuote(text, _):
|
||||
return markdownBlockQuote(text)
|
||||
case let .blockQuote(blocks, _):
|
||||
return markdownBlockQuoteBlocks(blocks)
|
||||
case let .pullQuote(text, _):
|
||||
return markdownBlockQuote(text)
|
||||
case let .list(items, ordered):
|
||||
|
|
@ -69,6 +69,19 @@ private func markdownBlockQuote(_ text: RichText) -> String {
|
|||
return lines.map { "> \($0)" }.joined(separator: "\n")
|
||||
}
|
||||
|
||||
private func markdownBlockQuoteBlocks(_ blocks: [InstantPageBlock]) -> String {
|
||||
var lines: [String] = []
|
||||
for block in blocks {
|
||||
guard let body = markdownString(from: block) else {
|
||||
continue
|
||||
}
|
||||
for line in body.split(separator: "\n", omittingEmptySubsequences: false) {
|
||||
lines.append("> \(String(line))")
|
||||
}
|
||||
}
|
||||
return lines.joined(separator: "\n")
|
||||
}
|
||||
|
||||
private func markdownInline(from richText: RichText) -> String {
|
||||
switch richText {
|
||||
case .empty:
|
||||
|
|
|
|||
|
|
@ -501,40 +501,65 @@ public func layoutInstantPageBlock(webpage: TelegramMediaWebpage, userLocation:
|
|||
}
|
||||
}
|
||||
return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: listItems)
|
||||
case let .blockQuote(text, caption):
|
||||
case let .blockQuote(blocks, caption):
|
||||
let lineInset: CGFloat = 20.0
|
||||
let verticalInset: CGFloat = 4.0
|
||||
var contentSize = CGSize(width: boundingWidth, height: verticalInset)
|
||||
|
||||
|
||||
var items: [InstantPageItem] = []
|
||||
|
||||
let styleStack = InstantPageTextStyleStack()
|
||||
setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false)
|
||||
styleStack.push(.italic)
|
||||
|
||||
let (_, textItems, textContentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, offset: CGPoint(x: horizontalInset + lineInset, y: contentSize.height), media: media, webpage: webpage, fitToWidth: fitToWidth)
|
||||
|
||||
contentSize.height += textContentSize.height
|
||||
items.append(contentsOf: textItems)
|
||||
|
||||
|
||||
let innerBoundingWidth = boundingWidth - horizontalInset * 2.0 - lineInset
|
||||
let innerHorizontalInset = horizontalInset + lineInset
|
||||
|
||||
if blocks.count == 1, case let .paragraph(text) = blocks[0] {
|
||||
// Legacy single-paragraph fast path: italicized body (unchanged from prior behavior).
|
||||
let styleStack = InstantPageTextStyleStack()
|
||||
setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false)
|
||||
styleStack.push(.italic)
|
||||
|
||||
let (_, textItems, textContentSize) = layoutTextItemWithString(attributedStringForRichText(text, styleStack: styleStack), boundingWidth: innerBoundingWidth, offset: CGPoint(x: innerHorizontalInset, y: contentSize.height), media: media, webpage: webpage, fitToWidth: fitToWidth)
|
||||
|
||||
contentSize.height += textContentSize.height
|
||||
items.append(contentsOf: textItems)
|
||||
} else {
|
||||
var previousChildItems: [InstantPageItem] = []
|
||||
// Fixed, compact gap between a quote's child blocks (the full page-flow
|
||||
// spacing around quotes is too airy when nested); the first child hugs
|
||||
// the top (only verticalInset above it).
|
||||
let childSpacing: CGFloat = 10.0
|
||||
for (i, child) in blocks.enumerated() {
|
||||
let childLayout = layoutInstantPageBlock(webpage: webpage, userLocation: userLocation, rtl: rtl, block: child, boundingWidth: innerBoundingWidth, horizontalInset: innerHorizontalInset, safeInset: safeInset, isCover: false, previousItems: previousChildItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight, excludeCaptions: excludeCaptions, isLast: i == blocks.count - 1 && isLast, fitToWidth: fitToWidth)
|
||||
let spacing: CGFloat = i == 0 ? 0.0 : childSpacing
|
||||
contentSize.height += spacing
|
||||
var childItems: [InstantPageItem] = []
|
||||
for var item in childLayout.items {
|
||||
item.frame = item.frame.offsetBy(dx: 0.0, dy: contentSize.height)
|
||||
childItems.append(item)
|
||||
}
|
||||
items.append(contentsOf: childItems)
|
||||
previousChildItems = childItems
|
||||
contentSize.height += childLayout.contentSize.height
|
||||
}
|
||||
}
|
||||
|
||||
if case .empty = caption {
|
||||
} else {
|
||||
contentSize.height += 14.0
|
||||
|
||||
|
||||
let styleStack = InstantPageTextStyleStack()
|
||||
setupStyleStack(styleStack, theme: theme, category: .caption, link: false)
|
||||
|
||||
let (_, captionItems, captionContentSize) = layoutTextItemWithString(attributedStringForRichText(caption, styleStack: styleStack), boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, offset: CGPoint(x: horizontalInset + lineInset, y: contentSize.height), media: media, webpage: webpage)
|
||||
|
||||
|
||||
let (_, captionItems, captionContentSize) = layoutTextItemWithString(attributedStringForRichText(caption, styleStack: styleStack), boundingWidth: innerBoundingWidth, offset: CGPoint(x: innerHorizontalInset, y: contentSize.height), media: media, webpage: webpage)
|
||||
|
||||
contentSize.height += captionContentSize.height
|
||||
items.append(contentsOf: captionItems)
|
||||
}
|
||||
contentSize.height += verticalInset
|
||||
|
||||
|
||||
let shapeItem = InstantPageShapeItem(frame: CGRect(origin: CGPoint(x: horizontalInset, y: 0.0), size: CGSize(width: 3.0, height: contentSize.height)), shapeFrame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: 3.0, height: contentSize.height)), shape: .roundLine, color: theme.textCategories.paragraph.color)
|
||||
|
||||
|
||||
items.append(shapeItem)
|
||||
|
||||
|
||||
return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items)
|
||||
case let .pullQuote(text, caption):
|
||||
let verticalInset: CGFloat = 4.0
|
||||
|
|
|
|||
|
|
@ -594,14 +594,14 @@ private func layoutBlock(
|
|||
return layoutCodeBlock(text, language: language, boundingWidth: boundingWidth,
|
||||
horizontalInset: horizontalInset, context: &context)
|
||||
|
||||
case let .blockQuote(text, caption):
|
||||
return layoutBlockQuote(text: text, caption: caption, isPull: false,
|
||||
case let .blockQuote(blocks, caption):
|
||||
return layoutBlockQuote(blocks: blocks, caption: caption,
|
||||
boundingWidth: boundingWidth, horizontalInset: horizontalInset,
|
||||
context: &context)
|
||||
isLast: isLast, context: &context)
|
||||
case let .pullQuote(text, caption):
|
||||
return layoutBlockQuote(text: text, caption: caption, isPull: true,
|
||||
boundingWidth: boundingWidth, horizontalInset: horizontalInset,
|
||||
context: &context)
|
||||
return layoutQuoteText(text: text, caption: caption, isPull: true,
|
||||
boundingWidth: boundingWidth, horizontalInset: horizontalInset,
|
||||
context: &context)
|
||||
|
||||
case let .image(id, caption, url, webpageId):
|
||||
if case let .image(image) = context.media[id], let largest = largestImageRepresentation(image.representations) {
|
||||
|
|
@ -1901,6 +1901,86 @@ private func layoutCodeBlock(
|
|||
// MARK: - Block quote / pull quote layout (ported from V1 InstantPageLayout.swift lines 517–586)
|
||||
|
||||
private func layoutBlockQuote(
|
||||
blocks: [InstantPageBlock],
|
||||
caption: RichText,
|
||||
boundingWidth: CGFloat,
|
||||
horizontalInset: CGFloat,
|
||||
isLast: Bool,
|
||||
context: inout LayoutContext
|
||||
) -> [InstantPageV2LaidOutItem] {
|
||||
// Legacy single-paragraph fast path: preserve today's italicized body styling.
|
||||
if blocks.count == 1, case let .paragraph(text) = blocks[0] {
|
||||
return layoutQuoteText(text: text, caption: caption, isPull: false,
|
||||
boundingWidth: boundingWidth, horizontalInset: horizontalInset,
|
||||
context: &context)
|
||||
}
|
||||
|
||||
let verticalInset: CGFloat = 4.0
|
||||
let lineInset: CGFloat = 20.0
|
||||
let barWidth: CGFloat = 3.0
|
||||
|
||||
let innerBoundingWidth = boundingWidth - horizontalInset * 2.0 - lineInset
|
||||
let innerHorizontalInset = horizontalInset + lineInset
|
||||
|
||||
var result: [InstantPageV2LaidOutItem] = []
|
||||
var contentHeight: CGFloat = verticalInset
|
||||
|
||||
// Fixed, compact gap between a quote's child blocks. The full page-flow spacing
|
||||
// (spacingBetweenBlocks ~27pt around quotes) is too airy when nested; the first
|
||||
// child hugs the top (only verticalInset above it).
|
||||
let childSpacing: CGFloat = 10.0
|
||||
for (i, child) in blocks.enumerated() {
|
||||
let spacing: CGFloat = i == 0 ? 0.0 : childSpacing
|
||||
let childItems = layoutBlock(
|
||||
child,
|
||||
boundingWidth: innerBoundingWidth,
|
||||
horizontalInset: innerHorizontalInset,
|
||||
isCover: false,
|
||||
previousItems: result,
|
||||
isLast: i == blocks.count - 1 && isLast,
|
||||
context: &context
|
||||
)
|
||||
let dy = contentHeight + spacing
|
||||
let offsetItems = childItems.map { $0.offsetBy(CGPoint(x: 0.0, y: dy)) }
|
||||
let childMaxY = offsetItems.map { $0.frame.maxY }.max() ?? dy
|
||||
contentHeight = max(contentHeight, childMaxY)
|
||||
result.append(contentsOf: offsetItems)
|
||||
}
|
||||
|
||||
// Optional caption (mirrors layoutQuoteText's caption branch).
|
||||
if case .empty = caption {
|
||||
// no caption
|
||||
} else {
|
||||
contentHeight += 14.0
|
||||
let captionStyleStack = InstantPageTextStyleStack()
|
||||
setupStyleStack(captionStyleStack, theme: context.theme, category: .caption, link: false)
|
||||
let attributedCaption = attributedStringForRichText(caption, styleStack: captionStyleStack)
|
||||
let (_, captionItems, captionSize) = layoutTextItem(
|
||||
attributedCaption,
|
||||
boundingWidth: innerBoundingWidth,
|
||||
alignment: .natural,
|
||||
offset: CGPoint(x: innerHorizontalInset, y: contentHeight),
|
||||
fitToWidth: context.fitToWidth,
|
||||
computeRevealCharacterRects: context.computeRevealCharacterRects
|
||||
)
|
||||
result.append(contentsOf: captionItems)
|
||||
contentHeight += captionSize.height
|
||||
}
|
||||
|
||||
contentHeight += verticalInset
|
||||
|
||||
// Vertical bar on the leading edge (matches the blockQuote branch of layoutQuoteText).
|
||||
let bar = InstantPageV2BarItem(
|
||||
frame: CGRect(x: horizontalInset, y: 0.0, width: barWidth, height: contentHeight),
|
||||
color: context.theme.textCategories.paragraph.color,
|
||||
cornerRadius: barWidth / 2.0
|
||||
)
|
||||
result.append(.blockQuoteBar(bar))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private func layoutQuoteText(
|
||||
text: RichText,
|
||||
caption: RichText,
|
||||
isPull: Bool,
|
||||
|
|
|
|||
|
|
@ -91,8 +91,9 @@ table InstantPageBlock_List {
|
|||
}
|
||||
|
||||
table InstantPageBlock_BlockQuote {
|
||||
text:RichText (id: 0, required);
|
||||
text:RichText (id: 0);
|
||||
caption:RichText (id: 1, required);
|
||||
blocks:[InstantPageBlock] (id: 2);
|
||||
}
|
||||
|
||||
table InstantPageBlock_PullQuote {
|
||||
|
|
|
|||
|
|
@ -246,7 +246,9 @@ extension InstantPageBlock {
|
|||
self = .anchor(name)
|
||||
case let .pageBlockBlockquote(pageBlockBlockquoteData):
|
||||
let (text, caption) = (pageBlockBlockquoteData.text, pageBlockBlockquoteData.caption)
|
||||
self = .blockQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
||||
self = .blockQuote(blocks: [.paragraph(RichText(apiText: text))], caption: RichText(apiText: caption))
|
||||
case let .pageBlockBlockquoteBlocks(pageBlockBlockquoteBlocksData):
|
||||
self = .blockQuote(blocks: pageBlockBlockquoteBlocksData.blocks.map { InstantPageBlock(apiBlock: $0) }, caption: RichText(apiText: pageBlockBlockquoteBlocksData.caption))
|
||||
case let .pageBlockPullquote(pageBlockPullquoteData):
|
||||
let (text, caption) = (pageBlockPullquoteData.text, pageBlockPullquoteData.caption)
|
||||
self = .pullQuote(text: RichText(apiText: text), caption: RichText(apiText: caption))
|
||||
|
|
@ -370,8 +372,14 @@ extension InstantPageBlock {
|
|||
} else {
|
||||
return .pageBlockList(Api.PageBlock.Cons_pageBlockList(items: items.map { $0.apiInputPageListItem() }))
|
||||
}
|
||||
case let .blockQuote(text, caption):
|
||||
return .pageBlockBlockquote(Api.PageBlock.Cons_pageBlockBlockquote(text: text.apiRichText(), caption: caption.apiRichText()))
|
||||
case let .blockQuote(blocks, caption):
|
||||
if blocks.isEmpty {
|
||||
return .pageBlockBlockquote(Api.PageBlock.Cons_pageBlockBlockquote(text: RichText.empty.apiRichText(), caption: caption.apiRichText()))
|
||||
}
|
||||
if blocks.count == 1, case let .paragraph(text) = blocks[0] {
|
||||
return .pageBlockBlockquote(Api.PageBlock.Cons_pageBlockBlockquote(text: text.apiRichText(), caption: caption.apiRichText()))
|
||||
}
|
||||
return .pageBlockBlockquoteBlocks(Api.PageBlock.Cons_pageBlockBlockquoteBlocks(blocks: blocks.compactMap { $0.apiInputBlock() }, caption: caption.apiRichText()))
|
||||
case let .pullQuote(text, caption):
|
||||
return .pageBlockPullquote(Api.PageBlock.Cons_pageBlockPullquote(text: text.apiRichText(), caption: caption.apiRichText()))
|
||||
case let .image(id, caption, url, webpageId):
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
case divider
|
||||
case anchor(String)
|
||||
case list(items: [InstantPageListItem], ordered: Bool)
|
||||
case blockQuote(text: RichText, caption: RichText)
|
||||
case blockQuote(blocks: [InstantPageBlock], caption: RichText)
|
||||
case pullQuote(text: RichText, caption: RichText)
|
||||
case image(id: MediaId, caption: InstantPageCaption, url: String?, webpageId: MediaId?)
|
||||
case video(id: MediaId, caption: InstantPageCaption, autoplay: Bool, loop: Bool)
|
||||
|
|
@ -121,7 +121,13 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
case InstantPageBlockType.list.rawValue:
|
||||
self = .list(items: decodeListItems(decoder), ordered: decoder.decodeOptionalInt32ForKey("o") != 0)
|
||||
case InstantPageBlockType.blockQuote.rawValue:
|
||||
self = .blockQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText)
|
||||
let caption = decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText
|
||||
if let legacyText = decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as? RichText {
|
||||
self = .blockQuote(blocks: [.paragraph(legacyText)], caption: caption)
|
||||
} else {
|
||||
let blocks: [InstantPageBlock] = decoder.decodeObjectArrayWithDecoderForKey("b")
|
||||
self = .blockQuote(blocks: blocks, caption: caption)
|
||||
}
|
||||
case InstantPageBlockType.pullQuote.rawValue:
|
||||
self = .pullQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText)
|
||||
case InstantPageBlockType.image.rawValue:
|
||||
|
|
@ -225,9 +231,9 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
encoder.encodeInt32(InstantPageBlockType.list.rawValue, forKey: "r")
|
||||
encoder.encodeObjectArray(items, forKey: "ml")
|
||||
encoder.encodeInt32(ordered ? 1 : 0, forKey: "o")
|
||||
case let .blockQuote(text, caption):
|
||||
case let .blockQuote(blocks, caption):
|
||||
encoder.encodeInt32(InstantPageBlockType.blockQuote.rawValue, forKey: "r")
|
||||
encoder.encodeObject(text, forKey: "t")
|
||||
encoder.encodeObjectArray(blocks, forKey: "b")
|
||||
encoder.encodeObject(caption, forKey: "c")
|
||||
case let .pullQuote(text, caption):
|
||||
encoder.encodeInt32(InstantPageBlockType.pullQuote.rawValue, forKey: "r")
|
||||
|
|
@ -445,8 +451,8 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
} else {
|
||||
return false
|
||||
}
|
||||
case let .blockQuote(text, caption):
|
||||
if case .blockQuote(text, caption) = rhs {
|
||||
case let .blockQuote(lhsBlocks, lhsCaption):
|
||||
if case let .blockQuote(rhsBlocks, rhsCaption) = rhs, lhsBlocks == rhsBlocks, lhsCaption == rhsCaption {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
|
|
@ -621,7 +627,15 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_BlockQuote.self) else {
|
||||
throw FlatBuffersError.missingRequiredField()
|
||||
}
|
||||
self = .blockQuote(text: try RichText(flatBuffersObject: value.text), caption: try RichText(flatBuffersObject: value.caption))
|
||||
let caption = try RichText(flatBuffersObject: value.caption)
|
||||
if value.blocksCount > 0 {
|
||||
let blocks = try (0 ..< value.blocksCount).map { try InstantPageBlock(flatBuffersObject: value.blocks(at: $0)!) }
|
||||
self = .blockQuote(blocks: blocks, caption: caption)
|
||||
} else if let legacyText = value.text {
|
||||
self = .blockQuote(blocks: [.paragraph(try RichText(flatBuffersObject: legacyText))], caption: caption)
|
||||
} else {
|
||||
self = .blockQuote(blocks: [], caption: caption)
|
||||
}
|
||||
case .instantpageblockPullquote:
|
||||
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_PullQuote.self) else {
|
||||
throw FlatBuffersError.missingRequiredField()
|
||||
|
|
@ -796,12 +810,13 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
|
|||
TelegramCore_InstantPageBlock_List.addVectorOf(items: itemsOffset, &builder)
|
||||
TelegramCore_InstantPageBlock_List.add(ordered: ordered, &builder)
|
||||
offset = TelegramCore_InstantPageBlock_List.endInstantPageBlock_List(&builder, start: start)
|
||||
case let .blockQuote(text, caption):
|
||||
case let .blockQuote(blocks, caption):
|
||||
valueType = .instantpageblockBlockquote
|
||||
let textOffset = text.encodeToFlatBuffers(builder: &builder)
|
||||
let blocksOffsets = blocks.map { $0.encodeToFlatBuffers(builder: &builder) }
|
||||
let blocksOffset = builder.createVector(ofOffsets: blocksOffsets, len: blocksOffsets.count)
|
||||
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
|
||||
let start = TelegramCore_InstantPageBlock_BlockQuote.startInstantPageBlock_BlockQuote(&builder)
|
||||
TelegramCore_InstantPageBlock_BlockQuote.add(text: textOffset, &builder)
|
||||
TelegramCore_InstantPageBlock_BlockQuote.addVectorOf(blocks: blocksOffset, &builder)
|
||||
TelegramCore_InstantPageBlock_BlockQuote.add(caption: captionOffset, &builder)
|
||||
offset = TelegramCore_InstantPageBlock_BlockQuote.endInstantPageBlock_BlockQuote(&builder, start: start)
|
||||
case let .pullQuote(text, caption):
|
||||
|
|
|
|||
|
|
@ -123,8 +123,9 @@ extension InstantPageBlock {
|
|||
result.append(item.previewText())
|
||||
}
|
||||
return result
|
||||
case let .blockQuote(text, caption):
|
||||
return text.previewText() + caption.previewText()
|
||||
case let .blockQuote(blocks, caption):
|
||||
let body = blocks.map { $0.previewText() }.joined(separator: " ")
|
||||
return body + caption.previewText()
|
||||
case let .pullQuote(text, caption):
|
||||
return text.previewText() + caption.previewText()
|
||||
case .image(_, _, _, _):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue