mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Cleanup
This commit is contained in:
parent
976c2de599
commit
2de1052c3d
3 changed files with 0 additions and 529 deletions
|
|
@ -1,410 +0,0 @@
|
|||
# Character Rects Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Compute per-line glyph bounding rects during layout and store them on `InteractiveTextNodeLine`, enabling `computeRevealedLines` and reveal animations to use pre-computed geometry.
|
||||
|
||||
**Architecture:** Replace `characterToGlyphMapping: [Int]?` on `InteractiveTextNodeLine` with `characterRects: [CGRect]?`. Add a `computeCharacterRects` flag to `InteractiveTextNodeLayoutArguments` that gates the computation. A new helper function computes actual glyph bounding boxes via `CTFontGetBoundingRectsForGlyphs`. Thread the flag through both `calculateLayout` and `calculateLayoutV2`, and update `computeRevealedLines` and `getCharacterToGlyphMapping` to consume the new data.
|
||||
|
||||
**Tech Stack:** Swift, CoreText (CTRun, CTFont, CTLine)
|
||||
|
||||
**File:** `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift`
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add `computeCharacterRects` flag to `InteractiveTextNodeLayoutArguments`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:281-362`
|
||||
|
||||
- [ ] **Step 1: Add the property declaration**
|
||||
|
||||
After line 299 (`public let expandedBlocks: Set<Int>`), add:
|
||||
|
||||
```swift
|
||||
public let computeCharacterRects: Bool
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add the init parameter**
|
||||
|
||||
In the `init` at line 301, after `expandedBlocks: Set<Int> = Set()`, add:
|
||||
|
||||
```swift
|
||||
computeCharacterRects: Bool = false
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add the assignment**
|
||||
|
||||
In the init body, after `self.expandedBlocks = expandedBlocks` (line 338), add:
|
||||
|
||||
```swift
|
||||
self.computeCharacterRects = computeCharacterRects
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Propagate through `withAttributedString`**
|
||||
|
||||
In the `withAttributedString` method (line 341), add after `expandedBlocks: self.expandedBlocks` (line 360):
|
||||
|
||||
```swift
|
||||
computeCharacterRects: self.computeCharacterRects
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: add computeCharacterRects flag to InteractiveTextNodeLayoutArguments"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Replace `characterToGlyphMapping` with `characterRects` on `InteractiveTextNodeLine`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:113-151`
|
||||
|
||||
- [ ] **Step 1: Replace the property declaration**
|
||||
|
||||
Change line 130 from:
|
||||
|
||||
```swift
|
||||
let characterToGlyphMapping: [Int]?
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```swift
|
||||
let characterRects: [CGRect]?
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update the init signature**
|
||||
|
||||
In the init at line 132, replace `characterToGlyphMapping: [Int]?` with `characterRects: [CGRect]?`.
|
||||
|
||||
- [ ] **Step 3: Update the init body**
|
||||
|
||||
Change line 149 from:
|
||||
|
||||
```swift
|
||||
self.characterToGlyphMapping = characterToGlyphMapping
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```swift
|
||||
self.characterRects = characterRects
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: replace characterToGlyphMapping with characterRects on InteractiveTextNodeLine"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Add `computeCharacterRects` helper function
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift` (insert before the `InteractiveTextNodeLine` class or after `addAttachment`, around line 1270)
|
||||
|
||||
- [ ] **Step 1: Write the helper function**
|
||||
|
||||
Insert a private free function near the other free helper functions (after `addAttachment` at ~line 1270):
|
||||
|
||||
```swift
|
||||
private func computeCharacterRectsForLine(line: CTLine, lineRange: NSRange) -> [CGRect] {
|
||||
var result = [CGRect](repeating: CGRect.zero, count: lineRange.length)
|
||||
|
||||
let glyphRuns = CTLineGetGlyphRuns(line) as NSArray
|
||||
for run in glyphRuns {
|
||||
let run = run as! CTRun
|
||||
let glyphCount = CTRunGetGlyphCount(run)
|
||||
if glyphCount == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var glyphs = [CGGlyph](repeating: 0, count: glyphCount)
|
||||
CTRunGetGlyphs(run, CFRangeMake(0, glyphCount), &glyphs)
|
||||
|
||||
var positions = [CGPoint](repeating: CGPoint.zero, count: glyphCount)
|
||||
CTRunGetPositions(run, CFRangeMake(0, glyphCount), &positions)
|
||||
|
||||
var stringIndices = [CFIndex](repeating: 0, count: glyphCount)
|
||||
CTRunGetStringIndices(run, CFRangeMake(0, glyphCount), &stringIndices)
|
||||
|
||||
let attributes = CTRunGetAttributes(run) as NSDictionary
|
||||
guard let font = attributes[kCTFontAttributeName] as! CTFont? else {
|
||||
continue
|
||||
}
|
||||
|
||||
var boundingRects = [CGRect](repeating: CGRect.zero, count: glyphCount)
|
||||
CTFontGetBoundingRectsForGlyphs(font, .default, &glyphs, &boundingRects, glyphCount)
|
||||
|
||||
for i in 0 ..< glyphCount {
|
||||
let charIndex = stringIndices[i] - lineRange.location
|
||||
if charIndex >= 0 && charIndex < lineRange.length {
|
||||
let pos = positions[i]
|
||||
let bbox = boundingRects[i]
|
||||
result[charIndex] = CGRect(
|
||||
x: pos.x + bbox.origin.x,
|
||||
y: pos.y + bbox.origin.y,
|
||||
width: bbox.width,
|
||||
height: bbox.height
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: add computeCharacterRectsForLine helper"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Thread `computeCharacterRects` through `calculateLayout` and `calculateLayoutV2`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:1433-1452,2045-2051`
|
||||
|
||||
- [ ] **Step 1: Add parameter to `calculateLayoutV2`**
|
||||
|
||||
At line 1433, the signature is `private static func calculateLayoutV2(...)`. After the last parameter `expandedBlocks: Set<Int>` (line 1451), add:
|
||||
|
||||
```swift
|
||||
computeCharacterRects: Bool
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add parameter to `calculateLayout`**
|
||||
|
||||
At line 2045, the signature is `static func calculateLayout(...)`. After `expandedBlocks: Set<Int>`, add:
|
||||
|
||||
```swift
|
||||
computeCharacterRects: Bool
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Pass through in `calculateLayout` body**
|
||||
|
||||
In the `calculateLayout` body, there are two calls to `calculateLayoutV2` (line 2050). Add `computeCharacterRects: computeCharacterRects` to both the early-return `InteractiveTextNodeLayout(...)` call (line 2047) — actually that one constructs a layout directly, not a call to V2, so skip it — and the `calculateLayoutV2(...)` call (line 2050). Add `computeCharacterRects: computeCharacterRects` as the last argument.
|
||||
|
||||
- [ ] **Step 4: Update the two `asyncLayout` call sites**
|
||||
|
||||
In `asyncLayout` (lines 2223 and 2226), there are two calls to `InteractiveTextNode.calculateLayout(...)`. Add `computeCharacterRects: arguments.computeCharacterRects` as the last argument to both.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: thread computeCharacterRects through calculateLayout and calculateLayoutV2"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Update all 4 `InteractiveTextNodeLine` construction sites
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:1619-1636,1661-1678,1720-1737,1775-1792`
|
||||
|
||||
- [ ] **Step 1: Title line construction (~line 1619)**
|
||||
|
||||
After `additionalTrailingLine: nil` (line 1635), add:
|
||||
|
||||
```swift
|
||||
characterRects: nil
|
||||
```
|
||||
|
||||
Title lines don't need character rects (they have `range: nil`).
|
||||
|
||||
- [ ] **Step 2: Main line construction (~line 1661)**
|
||||
|
||||
After `additionalTrailingLine: nil` (line 1677), add:
|
||||
|
||||
```swift
|
||||
characterRects: computeCharacterRects ? computeCharacterRectsForLine(line: line, lineRange: NSRange(location: currentLineStartIndex, length: lineCharacterCount)) : nil
|
||||
```
|
||||
|
||||
Note: `computeCharacterRects` here refers to the parameter passed into `calculateLayoutV2`. The `line` variable is the `CTLine` created on line 1646.
|
||||
|
||||
- [ ] **Step 3: Collapsed truncation construction (~line 1720)**
|
||||
|
||||
After `additionalTrailingLine: (truncationToken, 0.0)` (line 1736), add:
|
||||
|
||||
```swift
|
||||
characterRects: computeCharacterRects ? computeCharacterRectsForLine(line: updatedLine, lineRange: lastLine.range ?? NSRange()) : nil
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Final truncation construction (~line 1775)**
|
||||
|
||||
After `additionalTrailingLine: (truncationToken, truncationTokenWidth)` (line 1791), add:
|
||||
|
||||
```swift
|
||||
characterRects: computeCharacterRects ? computeCharacterRectsForLine(line: updatedLine, lineRange: lastLine.range ?? NSRange()) : nil
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: pass characterRects at all InteractiveTextNodeLine construction sites"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Implement `computeRevealedLines`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:2798-2852`
|
||||
|
||||
- [ ] **Step 1: Replace the stub with working implementation**
|
||||
|
||||
The function at line 2798 currently has a commented-out body and returns `[]`. Replace the body (keep the commented-out code above, don't delete it) so the full function reads:
|
||||
|
||||
```swift
|
||||
private func computeRevealedLines(lines: [InteractiveTextNodeLine], layerSize: CGSize, offset: CGPoint, characterLimit: Int) -> [RevealLineInfo] {
|
||||
/*var result: [RevealLineInfo] = []
|
||||
...existing commented code stays...
|
||||
return result*/
|
||||
//TODO
|
||||
var result: [RevealLineInfo] = []
|
||||
var remainingCharacters = characterLimit
|
||||
|
||||
for i in 0 ..< lines.count {
|
||||
let line = lines[i]
|
||||
|
||||
var lineFrame = line.frame
|
||||
lineFrame.origin.y += offset.y
|
||||
|
||||
if line.isRTL {
|
||||
lineFrame.origin.x = offset.x + floor(layerSize.width - lineFrame.width)
|
||||
lineFrame = displayLineFrame(frame: lineFrame, isRTL: true, boundingRect: CGRect(origin: CGPoint(), size: layerSize), cutout: nil)
|
||||
} else {
|
||||
lineFrame.origin.x += offset.x
|
||||
}
|
||||
|
||||
let lineHeight = line.ascent + line.descent
|
||||
|
||||
guard let characterRects = line.characterRects else {
|
||||
result.append(RevealLineInfo(lineFrame: lineFrame, lineHeight: lineHeight, revealedWidth: remainingCharacters > 0 ? lineFrame.width : 0.0, isFull: remainingCharacters > 0, isRTL: line.isRTL))
|
||||
continue
|
||||
}
|
||||
|
||||
if remainingCharacters <= 0 {
|
||||
result.append(RevealLineInfo(lineFrame: lineFrame, lineHeight: lineHeight, revealedWidth: 0.0, isFull: false, isRTL: line.isRTL))
|
||||
continue
|
||||
}
|
||||
|
||||
let revealCount = min(characterRects.count, remainingCharacters)
|
||||
var revealedWidth: CGFloat = 0.0
|
||||
for j in 0 ..< revealCount {
|
||||
let rect = characterRects[j]
|
||||
if !rect.isEmpty {
|
||||
revealedWidth = max(revealedWidth, rect.maxX)
|
||||
}
|
||||
}
|
||||
revealedWidth = ceil(revealedWidth)
|
||||
|
||||
remainingCharacters -= characterRects.count
|
||||
let isFull = remainingCharacters >= 0
|
||||
|
||||
result.append(RevealLineInfo(lineFrame: lineFrame, lineHeight: lineHeight, revealedWidth: revealedWidth, isFull: isFull, isRTL: line.isRTL))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: implement computeRevealedLines using characterRects"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Update `getCharacterToGlyphMapping`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift:2263-2270`
|
||||
|
||||
- [ ] **Step 1: Implement the method**
|
||||
|
||||
Replace the stub body of `getCharacterToGlyphMapping()` (lines 2263-2270) with:
|
||||
|
||||
```swift
|
||||
public func getCharacterToGlyphMapping() -> [Int] {
|
||||
/*guard let cachedLayout = self.cachedLayout else {
|
||||
return []
|
||||
}
|
||||
return cachedLayout.getCharacterToGlyphMapping()*/
|
||||
guard let cachedLayout = self.cachedLayout else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result: [Int] = []
|
||||
var cumulativeGlyphCount = 0
|
||||
|
||||
for segment in cachedLayout.segments {
|
||||
for line in segment.lines {
|
||||
if let characterRects = line.characterRects {
|
||||
for rect in characterRects {
|
||||
if !rect.isEmpty {
|
||||
cumulativeGlyphCount += 1
|
||||
}
|
||||
result.append(cumulativeGlyphCount)
|
||||
}
|
||||
} else {
|
||||
let glyphRuns = CTLineGetGlyphRuns(line.line) as NSArray
|
||||
for run in glyphRuns {
|
||||
let run = run as! CTRun
|
||||
let glyphCount = CTRunGetGlyphCount(run)
|
||||
for _ in 0 ..< glyphCount {
|
||||
cumulativeGlyphCount += 1
|
||||
result.append(cumulativeGlyphCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
This preserves the API contract: returns an array where each entry is the cumulative glyph count up to that character. When `characterRects` is available, characters with `.zero` rects (ligature components) don't increment the glyph count. When `characterRects` is `nil` (flag was off), it falls back to walking CTRuns directly (1:1 glyph-to-entry mapping).
|
||||
|
||||
- [ ] **Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "feat: implement getCharacterToGlyphMapping using characterRects"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Build verification
|
||||
|
||||
- [ ] **Step 1: Run the full build**
|
||||
|
||||
```bash
|
||||
PATH=/opt/homebrew/opt/ruby/bin:`gem environment gemdir`/bin:$PATH python3 build-system/Make/Make.py --overrideXcodeVersion --cacheDir ~/telegram-bazel-cache build --configurationPath build-system/appstore-configuration.json --gitCodesigningRepository git@gitlab.com:peter-iakovlev/fastlanematch.git --gitCodesigningType development --gitCodesigningUseCurrent --buildNumber 1 --configuration debug_sim_arm64
|
||||
```
|
||||
|
||||
Expected: Build succeeds with no errors related to `InteractiveTextComponent.swift`.
|
||||
|
||||
- [ ] **Step 2: Fix any compilation errors and re-run build if needed**
|
||||
|
||||
- [ ] **Step 3: Final commit if any fixes were needed**
|
||||
|
||||
```bash
|
||||
git add submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift
|
||||
git commit -m "fix: address build errors in character rects implementation"
|
||||
```
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
# Character Rects in InteractiveTextNodeLine
|
||||
|
||||
## Goal
|
||||
|
||||
Compute per-line character bounding rects (actual glyph drawn bounds) during the layout pass and store them on `InteractiveTextNodeLine`. This enables `computeRevealedLines` and the reveal animation system to work with precise glyph geometry without recomputing CoreText data at render time.
|
||||
|
||||
## File
|
||||
|
||||
`submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift`
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. InteractiveTextNodeLayoutArguments — new flag
|
||||
|
||||
Add a `computeCharacterRects: Bool` property (default `false`) to `InteractiveTextNodeLayoutArguments`.
|
||||
|
||||
- Add the property declaration, init parameter, and assignment.
|
||||
- Propagate through `withAttributedString`.
|
||||
|
||||
### 2. InteractiveTextNodeLine — replace characterToGlyphMapping with characterRects
|
||||
|
||||
Replace:
|
||||
```swift
|
||||
let characterToGlyphMapping: [Int]?
|
||||
```
|
||||
|
||||
With:
|
||||
```swift
|
||||
let characterRects: [CGRect]?
|
||||
```
|
||||
|
||||
Update the init signature and all construction sites (4 total: title line at ~1619, main line at ~1661, collapsed truncation at ~1720, final truncation at ~1775) to pass `characterRects` instead of `characterToGlyphMapping`.
|
||||
|
||||
- When `computeCharacterRects` is `false` in layout arguments, pass `nil`.
|
||||
- When `true`, compute the array at construction time (see section 3).
|
||||
|
||||
### 3. Glyph rect computation
|
||||
|
||||
A helper function (or inline logic) that, given a `CTLine` and its `NSRange`, produces `[CGRect]`:
|
||||
|
||||
1. Allocate an array of `CGRect.zero` with length equal to the line's string range length.
|
||||
2. For each `CTRun` in the line:
|
||||
a. Get glyphs via `CTRunGetGlyphs`.
|
||||
b. Get positions via `CTRunGetPositions` (glyph origins relative to the line).
|
||||
c. Get string indices via `CTRunGetStringIndices`.
|
||||
d. Get the font from the run's attributes (`kCTFontAttributeName`).
|
||||
e. Call `CTFontGetBoundingRectsForGlyphs(.default, glyphs, &boundingRects, glyphCount)` to get per-glyph bounding boxes relative to each glyph's origin.
|
||||
f. For each glyph at index `i`:
|
||||
- Compute the final rect: `CGRect(x: position.x + bbox.origin.x, y: position.y + bbox.origin.y, width: bbox.width, height: bbox.height)`.
|
||||
- Map to the character index: `stringIndices[i] - lineRangeStart`.
|
||||
- Store in the output array at that character index.
|
||||
3. Characters not covered by any glyph (ligature components, zero-width joiners, etc.) retain `.zero`.
|
||||
|
||||
### 4. computeRevealedLines — uncomment and adapt
|
||||
|
||||
The existing commented-out implementation at ~line 2798 walks CTRuns and uses `CTRunGetAdvances` to compute `revealedWidth`. Update it to use `characterRects` from the line instead:
|
||||
|
||||
- The function signature stays the same: `(lines: [InteractiveTextNodeLine], layerSize: CGSize, offset: CGPoint, characterLimit: Int) -> [RevealLineInfo]`.
|
||||
- Instead of walking CTRuns at call time, consume the pre-computed `characterRects` on each line to determine how many characters are revealed and what width they span.
|
||||
- `characterLimit` counts characters (one per entry in the `characterRects` arrays across all lines). Walk lines in order, decrementing the remaining character budget by each line's `characterRects.count`. For each line, the revealed width is the max x-extent of the revealed character rects within the budget.
|
||||
- Lines beyond the budget get `revealedWidth: 0`.
|
||||
|
||||
### 5. getCharacterToGlyphMapping — adapt
|
||||
|
||||
The public `getCharacterToGlyphMapping() -> [Int]` on `InteractiveTextNode` (line 2263) currently returns `[]`. Update it to derive a flat character count from the per-line `characterRects`:
|
||||
|
||||
- Walk all segments/lines, count the total number of character rects (including `.zero` entries for ligature components).
|
||||
- Return an array of cumulative glyph counts (preserving the existing API contract used by `ChatMessageTextBubbleContentNode` for animation counting).
|
||||
|
||||
The commented-out implementation on `InteractiveTextNodeLayout` (lines 1136-1190) stays as-is per user instruction.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Not changing `RevealLineInfo` struct shape.
|
||||
- Not touching `ChatMessageTextBubbleContentNode` in this task.
|
||||
- Not deleting any commented-out code.
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# layoutForCharacterCount Implementation
|
||||
|
||||
## Goal
|
||||
|
||||
Implement `layoutForCharacterCount` and `sizeForCharacterCount` on `InteractiveTextNodeLayout` so that `ChatMessageTextBubbleContentNode` can compute the text frame size and trailing line width during reveal animations.
|
||||
|
||||
## File
|
||||
|
||||
`submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift`
|
||||
|
||||
## Changes
|
||||
|
||||
### `layoutForCharacterCount(characterCount:) -> TextNodeLayout.LayoutInfo`
|
||||
|
||||
Replace the `preconditionFailure()` stub (keep the commented-out code above it).
|
||||
|
||||
Algorithm:
|
||||
|
||||
1. Initialize `height` from the first line's `frame.maxY` (same as commented-out code).
|
||||
2. Walk segments/lines, consuming the character budget. Each line's character count comes from `characterRects?.count` if available, otherwise from the line's `range?.length` (falling back to `CTLineGetStringRange`).
|
||||
3. For each line:
|
||||
- **Fully included** (remaining budget >= line's character count): use `line.frame.width` for that line's width contribution. Consume the line's characters from the budget.
|
||||
- **Cut line** (remaining budget > 0 but < line's character count): compute the string index at the cut point as `lineRange.location + remainingCharacters`. Call `CTLineGetOffsetForStringIndex(line.line, cutStringIndex, nil)` for the line width. This is the last contributing line.
|
||||
- **Beyond budget** (remaining budget <= 0): skip.
|
||||
4. Track `height` as the max `line.frame.maxY` across all contributing lines.
|
||||
5. Compute final values:
|
||||
- `width`: if more than one contributing line, use `self.size.width`; otherwise `ceil(maxLineWidth) + insets.left + insets.right`.
|
||||
- `height`: add `insets.top + insets.bottom + 2.0`.
|
||||
- `trailingLineWidth`: last contributing line's width + `insets.left + insets.right + 4.0`.
|
||||
6. Return `TextNodeLayout.LayoutInfo(size: CGSize(width: width, height: ceil(height)), trailingLineWidth: trailingLineWidth)`.
|
||||
|
||||
### `sizeForCharacterCount(characterCount:) -> CGSize`
|
||||
|
||||
Replace the `return CGSize()` stub with:
|
||||
|
||||
```swift
|
||||
return self.layoutForCharacterCount(characterCount: characterCount).size
|
||||
```
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Not deleting any commented-out code.
|
||||
- Not changing `ChatMessageTextBubbleContentNode`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue