ADFA-3583 | Automate image import for YOLO image placeholders#1243
ADFA-3583 | Automate image import for YOLO image placeholders#1243
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 Walkthrough
WalkthroughAdds placeholder-specific image selection: imports user-picked images into res/drawable, captures placeholder taps, stores per-placeholder drawable overrides in UI state, and propagates selected-image mappings through the XML generation pipeline to override ImageView src values. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Activity as ComputerVisionActivity
participant Zoomable as ZoomableImageView
participant ViewModel as ComputerVisionViewModel
participant Picker as ContentPicker
participant Importer as DrawableImportHelper
participant Repo as ComputerVisionRepository
User->>Zoomable: Tap on image
Zoomable->>Zoomable: mapViewPointToImage(x,y)
Zoomable->>Activity: onImageTapListener(imageX,imageY)
Activity->>ViewModel: ImagePlaceholderTapped(imageX,imageY)
ViewModel->>ViewModel: hit-test placeholder → pendingImagePlaceholderId
ViewModel->>Activity: Emit OpenPlaceholderImagePicker
Activity->>Picker: Launch
User->>Picker: Select image (Uri)
Picker->>Activity: Return Uri
Activity->>ViewModel: PlaceholderImageSelected(uri)
ViewModel->>Importer: importDrawable(uri, layoutFilePath, fallbackName)
Importer->>Importer: sanitize name, copy to res/drawable
Importer-->>ViewModel: Result(ImportedDrawable)
ViewModel->>ViewModel: record selectedImagesByPlaceholderId[id]=drawableRef
ViewModel->>Repo: generateXml(..., selectedImagesByPlaceholderId)
Repo->>Repo: forward to YoloToXmlConverter / AndroidXmlGenerator
Repo->>Activity: Return generated XML (with drawable overrides)
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
1f44271 to
b56fa24
Compare
Adds tap listener and file picker to map selected device images to detected placeholders, copying them to the drawable folder.
b56fa24 to
00e0215
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt (1)
6-11: Consider removing or redesigning unusedisCanvasMetadata()method.
TextCleaner.isCanvasMetadata()is not currently called anywhere in the codebase. However, if it were to be used with text processed bycleanText(), the method would fail to match metadata keywords sincecleanText()removes underscores (via the[^a-zA-Z0-9 ]regex) but the keywords use underscores:"layout_width","layout_height", etc.The method should either be removed as dead code or redesigned to normalize keywords matching the text-cleaning strategy used elsewhere.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt` around lines 6 - 11, isCanvasMetadata() is unused and, if kept, will fail to match text cleaned by cleanText() because cleanText() strips underscores and non-alphanumerics while METADATA_KEYWORDS contain underscores; either remove isCanvasMetadata() entirely or update its logic to normalize both sides (e.g., apply the same cleaning/normalization as cleanText() to input text and to each METADATA_KEYWORDS entry or store a normalized keyword list without underscores) and keep the function name isCanvasMetadata() to perform the normalized comparison against METADATA_KEYWORDS.cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.kt (1)
10-10: Strengthen placeholder sort tie-breakers for stable index mapping.The placeholder-id mapping (
ph_0,ph_1, …) depends on consistent ordering; top/left (or y/x) ties can make that less stable. Add extra keys to reduce collisions.Proposed refactor
fun List<DetectionResult>.getSortedPlaceholders(): List<DetectionResult> { return this.filter { it.label == IMAGE_PLACEHOLDER_LABEL } - .sortedWith(compareBy({ it.boundingBox.top }, { it.boundingBox.left })) + .sortedWith( + compareBy<DetectionResult>( + { it.boundingBox.top }, + { it.boundingBox.left }, + { it.boundingBox.bottom }, + { it.boundingBox.right } + ) + ) } fun List<ScaledBox>.getSortedScaledPlaceholders(): List<ScaledBox> { return this.filter { it.label == IMAGE_PLACEHOLDER_LABEL } - .sortedWith(compareBy({ it.y }, { it.x })) + .sortedWith(compareBy({ it.y }, { it.x }, { it.h }, { it.w })) }Also applies to: 15-15
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.kt` at line 10, The sort comparator using compareBy({ it.boundingBox.top }, { it.boundingBox.left }) is too weak and can produce unstable ordering when top/left tie; update the sorter in PlaceholderUtils (the sortedWith call) to add additional tie-breakers such as boundingBox.bottom, boundingBox.right (or width/height), and finally a deterministic fallback like the object's id or hashCode to guarantee stable ph_0/ph_1 mapping; ensure the comparator preserves the same top-then-left primary ordering but appends these extra keys in order of significance.cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.kt (1)
70-80: Centralize placeholder ID generation.This method hardcodes
ph_$index, andComputerVisionViewModel.resolvePlaceholderId()does the same from a separately sorted detection list. That coupling works today, but any future sort/filter tweak on either side will silently bind the wrong drawable to the wrong placeholder. Please move the ID generation into a shared helper used by both layers.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.kt` around lines 70 - 80, The method buildSelectedImageOverrides currently hardcodes placeholder IDs using "ph_$index", which duplicates the logic in ComputerVisionViewModel.resolvePlaceholderId() and risks mismatches; extract the ID generation into a shared helper (e.g., a top-level function or companion object method named generatePlaceholderId(index: Int) or placeholderIdFor(index: Int)), replace the hardcoded "ph_$index" in buildSelectedImageOverrides with a call to that helper, and update ComputerVisionViewModel.resolvePlaceholderId() to use the same helper so both layers derive placeholder IDs from the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.kt`:
- Around line 60-63: The current normalization in AttributeValidator (the
assignment to variable 'content' derived from 'trimmed') unconditionally strips
leading/trailing bracket-like characters and can corrupt values; change this to
only unwrap when the first character is a bracket from the opening set and the
last character is the corresponding matching closing bracket (i.e., perform a
pair-aware check for matching pairs before removing them). Locate the code that
sets 'content' in AttributeValidator.kt, examine 'trimmed', and replace the
unconditional .replace(...) calls with logic that checks trimmed.first() and
trimmed.last() for matching pairs ((), {}, [], <>) and only then removes the
outer characters; otherwise leave the string intact. Ensure the behavior is
unit-testable and preserves original whitespace trimming.
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt`:
- Around line 409-425: The success handler for importDrawable may apply a stale
placeholderId because placeholderId is captured before the async work; change
the state mutation in the onSuccess block to guard against stale imports by
checking the current _uiState.pendingImagePlaceholderId matches the captured
placeholderId before updating selectedImagesByPlaceholderId and clearing
pendingImagePlaceholderId. Concretely, inside the onSuccess { importedDrawable
-> ... } use _uiState.update { currentState -> if
(currentState.pendingImagePlaceholderId != placeholderId) currentState else
currentState.copy(pendingImagePlaceholderId = null,
selectedImagesByPlaceholderId = currentState.selectedImagesByPlaceholderId +
(placeholderId to SelectedImportedImage(...))) } so only the intended
placeholder is mutated.
---
Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.kt`:
- Around line 70-80: The method buildSelectedImageOverrides currently hardcodes
placeholder IDs using "ph_$index", which duplicates the logic in
ComputerVisionViewModel.resolvePlaceholderId() and risks mismatches; extract the
ID generation into a shared helper (e.g., a top-level function or companion
object method named generatePlaceholderId(index: Int) or placeholderIdFor(index:
Int)), replace the hardcoded "ph_$index" in buildSelectedImageOverrides with a
call to that helper, and update ComputerVisionViewModel.resolvePlaceholderId()
to use the same helper so both layers derive placeholder IDs from the single
source of truth.
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.kt`:
- Line 10: The sort comparator using compareBy({ it.boundingBox.top }, {
it.boundingBox.left }) is too weak and can produce unstable ordering when
top/left tie; update the sorter in PlaceholderUtils (the sortedWith call) to add
additional tie-breakers such as boundingBox.bottom, boundingBox.right (or
width/height), and finally a deterministic fallback like the object's id or
hashCode to guarantee stable ph_0/ph_1 mapping; ensure the comparator preserves
the same top-then-left primary ordering but appends these extra keys in order of
significance.
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.kt`:
- Around line 6-11: isCanvasMetadata() is unused and, if kept, will fail to
match text cleaned by cleanText() because cleanText() strips underscores and
non-alphanumerics while METADATA_KEYWORDS contain underscores; either remove
isCanvasMetadata() entirely or update its logic to normalize both sides (e.g.,
apply the same cleaning/normalization as cleanText() to input text and to each
METADATA_KEYWORDS entry or store a normalized keyword list without underscores)
and keep the function name isCanvasMetadata() to perform the normalized
comparison against METADATA_KEYWORDS.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cd77068a-fe0c-4251-b970-d7b677c26523
📒 Files selected for processing (18)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/ComputerVisionRepository.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/ComputerVisionRepositoryImpl.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/di/ComputerVisionModule.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/MarginAnnotationParser.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/AttributeValidator.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidXmlGenerator.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/LayoutRenderer.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionActivity.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionEvent.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionUiState.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ZoomableImageView.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/TextCleaner.ktcv-image-to-xml/src/main/res/values/strings.xml
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.kt (1)
19-43: Prefer narrow exception handling over broadrunCatchinghere.This currently collapses all failures into a generic
Resultpath. Catch only expected exceptions (IllegalArgumentException,IllegalStateException, I/O/security exceptions) and let unexpected programmer/runtime bugs fail fast.Based on learnings: In Kotlin files across this project, prefer narrow exception handling (for example,
IllegalArgumentException) over broad catch-all handling to preserve fail-fast behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.kt` around lines 19 - 43, The current runCatching block in the function that produces Result<ImportedDrawable> should be replaced with a try block that only catches expected exceptions (e.g., IllegalArgumentException, IllegalStateException, IOException, SecurityException) and returns a failed Result for those, while allowing other unexpected exceptions to propagate; specifically wrap the sequence that calls requireNotNull(layoutFilePath), resolveDrawableDir(...), resolveSupportedExtension(sourceUri), sanitizeResourceName(...), resolveAvailableFile(...), and the contentResolver.openInputStream(...) copy in the try, catch the listed exception types and return Result.failure(...) for them, and do not catch Throwable or Exception broadly so programmer/runtime bugs in methods like resolveDrawableDir, resolveSupportedExtension, sanitizeResourceName, resolveAvailableFile, or ImportedDrawable construction will fail fast.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.kt`:
- Around line 91-102: The current resolveAvailableFile uses candidate.exists()
which has a TOCTOU race; change resolveAvailableFile to attempt atomic
reservation by repeatedly constructing candidate (using drawableDir, baseName,
extension), calling candidate.createNewFile() and returning the File as soon as
createNewFile() returns true; if createNewFile() returns false (file already
exists) increment the index and retry; catch and handle IOExceptions
appropriately (either retry on transient errors or bubble up a clear exception)
so you don't return a filename that wasn't actually reserved.
- Around line 61-71: The resolveSupportedExtension function is too strict: if
resolveDisplayName(uri) returns null or has no extension it immediately rejects
valid images; update resolveSupportedExtension to try
ContentResolver.getType(uri) to derive a MIME-based extension (e.g., image/png,
image/jpeg, image/webp) and, if that fails, use the existing fallbackName (or
another fallback) before throwing; map MIME types to the same allowed strings
("png","jpg","jpeg","webp"), keep the final validation logic as in
resolveSupportedExtension, and reference resolveDisplayName,
resolveSupportedExtension, ContentResolver.getType, and fallbackName when making
the changes.
---
Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.kt`:
- Around line 19-43: The current runCatching block in the function that produces
Result<ImportedDrawable> should be replaced with a try block that only catches
expected exceptions (e.g., IllegalArgumentException, IllegalStateException,
IOException, SecurityException) and returns a failed Result for those, while
allowing other unexpected exceptions to propagate; specifically wrap the
sequence that calls requireNotNull(layoutFilePath), resolveDrawableDir(...),
resolveSupportedExtension(sourceUri), sanitizeResourceName(...),
resolveAvailableFile(...), and the contentResolver.openInputStream(...) copy in
the try, catch the listed exception types and return Result.failure(...) for
them, and do not catch Throwable or Exception broadly so programmer/runtime bugs
in methods like resolveDrawableDir, resolveSupportedExtension,
sanitizeResourceName, resolveAvailableFile, or ImportedDrawable construction
will fail fast.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5237a720-a48e-4e8d-98d2-7a31040d6987
📒 Files selected for processing (15)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/ComputerVisionRepository.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/ComputerVisionRepositoryImpl.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/di/ComputerVisionModule.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidXmlGenerator.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/LayoutRenderer.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionActivity.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionEvent.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionUiState.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ZoomableImageView.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.ktcv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.ktcv-image-to-xml/src/main/res/values/strings.xml
✅ Files skipped from review due to trivial changes (2)
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionEvent.kt
- cv-image-to-xml/src/main/res/values/strings.xml
🚧 Files skipped from review as they are similar to previous changes (9)
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/grammar/WidgetGrammar.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/AndroidXmlGenerator.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/di/ComputerVisionModule.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/xml/LayoutRenderer.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/PlaceholderUtils.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionUiState.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionActivity.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/YoloToXmlConverter.kt
- cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
Description
Added functionality to allow users to tap on an image placeholder detected by the YOLO model, pick an image from their filesystem, and automatically import it. The image is safely copied to the corresponding
res/drawablefolder, and the generated XML layout is updated to reference the new drawable usingandroid:src.Details
DrawableImportHelperto handle resolving the resource directory, sanitizing filenames, avoiding duplicates, and copying the image stream.ZoomableImageViewto add anonImageTapListenerthat maps view touch coordinates to the original image coordinates.ComputerVisionViewModelto handle placeholder tap events, trigger the content picker, and maintain the state of selected images mapped by placeholder ID.YoloToXmlConverterandLayoutRendererto inject the new@drawable/...references into the generated Android XML tags.document_5143474614021655795.mp4
Ticket
ADFA-3583
Observation
The
DrawableImportHelpersafely handles special characters in image names and ensures a fallback name is provided. It dynamically traverses the directory tree from the provided layout file path to locate the rootres/drawablefolder for injection.