From 0ba7a54e30c7140e7999fb0d341f466468634931 Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Tue, 28 Apr 2026 13:43:58 -0500 Subject: [PATCH 1/2] fix: enhance dropdown parsing and refine metadata detection Add trailing glyph removal for spinner entries, allow empty canvas tags, and remove broad assignment regex. --- .../domain/MarginAnnotationParser.kt | 2 +- .../domain/xml/AndroidWidget.kt | 47 +++++++++++++++---- .../computervision/utils/MetadataDetector.kt | 6 +-- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.kt index b767b9054d..7ab86088a5 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.kt @@ -125,7 +125,7 @@ object MarginAnnotationParser { for (block in explicitBlocks) { val tag = block.tag ?: continue - if (canvasTags.any { (canvasTag, _) -> canvasTag == tag }) { + if (canvasTags.isEmpty() || canvasTags.any { (canvasTag, _) -> canvasTag == tag }) { annotationMap[tag] = block.annotationText } } diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt index 5c8cb6cc0b..e7c5f989d0 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt @@ -88,20 +88,51 @@ class SpinnerWidget( override fun processAttributes(context: XmlContext, id: String, attrs: Map): Map { val processed = mutableMapOf() + val rawEntries = attrs[AttributeKey.ENTRIES.xmlName] + ?: attrs[AttributeKey.TEXT.xmlName] + ?: box.text.takeIf { it.isMeaningfulDropdownText() } + + when { + rawEntries == null -> Unit + rawEntries.startsWith("@") -> { + processed[AttributeKey.ENTRIES.xmlName] = rawEntries.escapeXmlAttr() + } + else -> rawEntries + .toSpinnerEntries() + .takeIf { it.isNotEmpty() } + ?.let { items -> + val arrayName = "${id}_array" + context.stringArrays[arrayName] = items + processed[AttributeKey.ENTRIES.xmlName] = "@array/$arrayName" + } + } attrs.forEach { (key, value) -> - if (key == AttributeKey.ENTRIES.xmlName && !value.startsWith("@")) { - val arrayName = "${id}_array" - val items = value.split(",").map { it.trim() }.filter { it.isNotEmpty() } - - context.stringArrays[arrayName] = items - processed[key] = "@array/$arrayName" - } else { - processed[key] = value.escapeXmlAttr() + when { + key == AttributeKey.ENTRIES.xmlName || key == AttributeKey.TEXT.xmlName -> Unit + else -> processed[key] = value.escapeXmlAttr() } } return processed } + + private fun String.toSpinnerEntries(): List { + return removeTrailingDropdownGlyph() + .split(Regex("\\s*[,;|/\\n]+\\s*")) + .map { it.trim() } + .filter { it.isNotEmpty() } + } + + private fun String.removeTrailingDropdownGlyph(): String { + return trim() + .replace(Regex("\\s*[▼▽▾▿⌄˅∨vV]$"), "") + .trim() + } + + private fun String.isMeaningfulDropdownText(): Boolean { + val cleaned = removeTrailingDropdownGlyph() + return cleaned.isNotBlank() && !cleaned.equals("dropdown", ignoreCase = true) + } } class TextBasedWidget( diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/MetadataDetector.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/MetadataDetector.kt index 416e380632..68cee4064a 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/MetadataDetector.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/MetadataDetector.kt @@ -31,17 +31,13 @@ object MetadataDetector { ) private val xmlAttributeRegex = Regex("""\b(?:android|app|tools):[a-zA-Z_]+\b""") - private val assignmentRegex = Regex("""\b[a-zA-Z_]+(?:[:=])[^\s]+""") - fun isCanvasMetadata(text: String): Boolean { val lowerText = text.lowercase() if (lowerText.isBlank()) return false if (metadataSnippets.any { snippet -> lowerText.contains(snippet) }) return true if (xmlAttributeRegex.containsMatchIn(lowerText)) return true if (metadataKeywords.any { keyword -> lowerText.contains(keyword) }) return true - - val assignmentCount = assignmentRegex.findAll(lowerText).count() - return assignmentCount >= 2 + return false } fun isMetadataLabel(label: String): Boolean { From e23027b4bfa5a56f06c9106c500f00cebde333da Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Tue, 28 Apr 2026 13:54:08 -0500 Subject: [PATCH 2/2] fix: `removeTrailingDropdownGlyph` regex and trim raw entries --- .../codeonthego/computervision/domain/xml/AndroidWidget.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt index e7c5f989d0..0c28f67adb 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidWidget.kt @@ -94,8 +94,8 @@ class SpinnerWidget( when { rawEntries == null -> Unit - rawEntries.startsWith("@") -> { - processed[AttributeKey.ENTRIES.xmlName] = rawEntries.escapeXmlAttr() + rawEntries.trimStart().startsWith("@") -> { + processed[AttributeKey.ENTRIES.xmlName] = rawEntries.trim().escapeXmlAttr() } else -> rawEntries .toSpinnerEntries() @@ -125,7 +125,7 @@ class SpinnerWidget( private fun String.removeTrailingDropdownGlyph(): String { return trim() - .replace(Regex("\\s*[▼▽▾▿⌄˅∨vV]$"), "") + .replace(Regex("\\s*[▼▽▾▿⌄˅∨]$|\\s+[vV]$"), "") .trim() }