Added a data structure for ParagraphImageAnalysis

Single pass analysis
All image-related decisions are made based on the single analysis result
This commit is contained in:
davotoula
2025-09-14 12:10:59 +02:00
parent 7e80ed2af9
commit 74cc9535ac

View File

@@ -358,39 +358,36 @@ private fun renderParagraphWithFlowRow(
): Int { ): Int {
val paragraph = paragraphs[paragraphIndex] val paragraph = paragraphs[paragraphIndex]
// Check if this paragraph contains only images (ignoring whitespace) if (paragraph.words.isEmpty()) {
val isImageOnlyParagraph = isImageOnlyParagraph(paragraph) // Empty paragraph - render normally with FlowRow (will render nothing)
// Check if this paragraph contains multiple images (mixed with text is ok) RenderSingleParagraphWithFlowRow(paragraph, paragraph.words.toImmutableList(), spaceWidth, context)
val hasMultipleImages = hasMultipleImages(paragraph) return paragraphIndex + 1
}
if (isImageOnlyParagraph && paragraph.words.isNotEmpty()) { val analysis = analyzeParagraphImages(paragraph)
if (analysis.isImageOnly) {
// Collect consecutive image-only paragraphs for gallery // Collect consecutive image-only paragraphs for gallery
val (imageParagraphs, endIndex) = collectConsecutiveImageParagraphs(paragraphs, paragraphIndex) val (imageParagraphs, endIndex) = collectConsecutiveImageParagraphs(paragraphs, paragraphIndex)
val allImageWords = imageParagraphs.flatMap { it.words }.toImmutableList() val allImageWords = imageParagraphs.flatMap { it.words }.toImmutableList()
if (allImageWords.size > 1) { if (allImageWords.size > 1) {
// Multiple images - render as gallery (no FlowRow wrapper needed) // Multiple images - render as gallery (no FlowRow wrapper needed)
RenderWordsWithImageGallery( RenderWordsWithImageGallery(allImageWords, context)
allImageWords,
context,
)
} else { } else {
// Single image - render with FlowRow wrapper // Single image - render with FlowRow wrapper
RenderSingleParagraphWithFlowRow(paragraph, paragraph.words.toImmutableList(), spaceWidth, context) RenderSingleParagraphWithFlowRow(paragraph, paragraph.words.toImmutableList(), spaceWidth, context)
} }
return endIndex // Return next index to process return endIndex // Return next index to process
} else if (hasMultipleImages && paragraph.words.isNotEmpty()) { } else if (analysis.hasMultipleImages) {
// Mixed paragraph with multiple images - use RenderWordsWithImageGallery for smart grouping // Mixed paragraph with multiple images - use RenderWordsWithImageGallery for smart grouping
RenderWordsWithImageGallery( RenderWordsWithImageGallery(paragraph.words.toImmutableList(), context)
paragraph.words.toImmutableList(), return paragraphIndex + 1
context,
)
return paragraphIndex + 1 // Return next index to process
} else { } else {
// Non-image paragraph - render normally with FlowRow // Regular paragraph (no images or single image) - render normally with FlowRow
RenderSingleParagraphWithFlowRow(paragraph, paragraph.words.toImmutableList(), spaceWidth, context) RenderSingleParagraphWithFlowRow(paragraph, paragraph.words.toImmutableList(), spaceWidth, context)
return paragraphIndex + 1 // Return next index to process return paragraphIndex + 1
} }
} }
@@ -420,29 +417,36 @@ private fun RenderSingleParagraphWithFlowRow(
} }
} }
private fun isImageOnlyParagraph(paragraph: ParagraphState): Boolean { data class ParagraphImageAnalysis(
// A paragraph is "image only" if all non-whitespace words are images val imageCount: Int,
val nonWhitespaceWords = val isImageOnly: Boolean,
paragraph.words.filter { word -> val hasMultipleImages: Boolean,
when (word) { )
is RegularTextSegment -> word.segmentText.isNotBlank()
else -> true // All other word types (images, links, etc.) are considered non-whitespace private fun analyzeParagraphImages(paragraph: ParagraphState): ParagraphImageAnalysis {
var imageCount = 0
var hasNonWhitespaceNonImageContent = false
paragraph.words.forEach { word ->
when (word) {
is ImageSegment, is Base64Segment -> imageCount++
is RegularTextSegment -> {
if (word.segmentText.isNotBlank()) {
hasNonWhitespaceNonImageContent = true
}
} }
else -> hasNonWhitespaceNonImageContent = true // Links, emojis, etc.
} }
}
return nonWhitespaceWords.isNotEmpty() && val isImageOnly = imageCount > 0 && !hasNonWhitespaceNonImageContent
nonWhitespaceWords.all { word -> val hasMultipleImages = imageCount > 1
word is ImageSegment || word is Base64Segment
}
}
private fun hasMultipleImages(paragraph: ParagraphState): Boolean { return ParagraphImageAnalysis(
// Count the number of image segments in the paragraph imageCount = imageCount,
val imageCount = isImageOnly = isImageOnly,
paragraph.words.count { word -> hasMultipleImages = hasMultipleImages,
word is ImageSegment || word is Base64Segment )
}
return imageCount > 1
} }
private fun collectConsecutiveImageParagraphs( private fun collectConsecutiveImageParagraphs(
@@ -471,8 +475,9 @@ private fun collectConsecutiveImageParagraphs(
} }
} }
// Check if it's an image-only paragraph // Check if it's an image-only paragraph using unified analysis
if (isImageOnlyParagraph(currentParagraph)) { val analysis = analyzeParagraphImages(currentParagraph)
if (analysis.isImageOnly) {
imageParagraphs.add(currentParagraph) imageParagraphs.add(currentParagraph)
j++ j++
} else { } else {