Skip to content

ADFA-3972 | Add visual hints for image placeholders#1287

Merged
jatezzz merged 3 commits into
stagefrom
feat/ADFA-3972-image-placeholder-visuals-experimental
May 11, 2026
Merged

ADFA-3972 | Add visual hints for image placeholders#1287
jatezzz merged 3 commits into
stagefrom
feat/ADFA-3972-image-placeholder-visuals-experimental

Conversation

@jatezzz
Copy link
Copy Markdown
Collaborator

@jatezzz jatezzz commented May 8, 2026

Description

Added visual indicators (upload and delete badges) to YOLO-detected image placeholders. This provides users with clear, actionable feedback that they can tap on the bounding box to import or remove an image, addressing the lack of visual cues on placeholders.

Details

  • Extracted rendering and bounding box drawing logic from ComputerVisionActivity into a new DetectionVisualizer class.
  • Added new vector icons (ic_placeholder_upload and ic_placeholder_delete) and integrated them as badges on image placeholders.
  • Updated touch event routing to distinguish between general placeholder taps (for importing) and delete badge taps (for removal).
  • Extracted XML file saving functionality into a new XmlFileManager class.
  • Updated ComputerVisionViewModel and DrawableImportHelper with robust file deletion logic to cleanly remove imported images from the project.
document_5186007705218713965.mp4

Ticket

ADFA-3972

Observation

Refactoring the ComputerVisionActivity to delegate visualization (DetectionVisualizer) and file saving (XmlFileManager) significantly reduces its bloat and adheres closer to the Single Responsibility Principle, making future UI/canvas modifications much easier to manage.

@jatezzz jatezzz requested review from a team, Daniel-ADFA and avestaadfa May 8, 2026 21:49
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

Warning

Rate limit exceeded

@jatezzz has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 39 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 67c56aaf-fb93-4d10-85a3-54a03bd8c347

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdb6c4 and 2de2ad8.

📒 Files selected for processing (9)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.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/ui/ComputerVisionEvent.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt
  • cv-image-to-xml/src/main/res/drawable/ic_placeholder_delete.xml
  • cv-image-to-xml/src/main/res/drawable/ic_placeholder_upload.xml
  • cv-image-to-xml/src/main/res/values/strings.xml
📝 Walkthrough

Walkthrough

This PR extracts detection rendering and XML persistence into utilities (DetectionVisualizer, XmlFileManager), refactors DrawableImportHelper with private helpers and a new suspend deleteDrawable API, adds a RemovePlaceholderImage event, and wires deletion through the ViewModel and Activity (tap handling, toasts, and file-save delegation).

Changes

Placeholder Image Deletion Flow

Layer / File(s) Summary
Event Contracts
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionEvent.kt
New RemovePlaceholderImage(placeholderId: String) event enables UI to request placeholder deletion.
Data Layer & Drawable Management
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.kt
importDrawable delegates to private helpers (getOrCreateDrawableDirectory, copyImageToDestination, findFileByResourceName). New suspend fun deleteDrawable(layoutFilePath: String?, resourceName: String): Result<Boolean> removes imported drawables by resource name.
Visualization Utility
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt
New DetectionVisualizer renders detections onto bitmaps, assigns deterministic placeholder IDs (ph_$index), records clickable badge rectangles for delete icons, exposes visualize(...), getTappedDeleteIconId(...), and clearCache().
Persistence Utility
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt
New XmlFileManager saves XML to Downloads using MediaStore on Android Q+ or legacy external Downloads on older versions; saveXmlToDownloads returns Result<String>.
Activity Refactoring
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionActivity.kt
Activity lazily instantiates DetectionVisualizer and XmlFileManager, delegates overlay rendering in updateUi, adds handleImageTap to route delete-icon vs placeholder taps, uses new saveXmlFile delegating to XmlFileManager, splits lifecycle collectors, and removes local bitmap-drawing and save helpers.
ViewModel Event Handling
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
onEvent handles RemovePlaceholderImage by calling removePlaceholderImage(placeholderId), which invokes drawableImportHelper.deleteDrawable(...), updates selectedImagesByPlaceholderId on success, and emits toast (R.string.msg_image_removed) or error effect on failure.
Resources
cv-image-to-xml/src/main/res/drawable/ic_placeholder_*.xml, cv-image-to-xml/src/main/res/values/strings.xml
Adds ic_placeholder_upload.xml and ic_placeholder_delete.xml vector drawables and msg_image_removed string resource ("Image deleted from the project").

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Activity
  participant ViewModel
  participant DI as DrawableImportHelper
  participant Visualizer as DetectionVisualizer
  participant FileManager as XmlFileManager

  User->>Activity: tap image (x,y)
  Activity->>Visualizer: getTappedDeleteIconId(x,y)
  alt delete icon tapped
    Activity->>ViewModel: RemovePlaceholderImage(placeholderId)
    ViewModel->>DI: deleteDrawable(layoutFilePath, resourceName)
    DI-->>ViewModel: Result<Boolean>
    ViewModel-->>Activity: Show toast / ShowError
  else placeholder tapped
    Activity->>ViewModel: ImagePlaceholderTapped(...)
  end

  ViewModel->>Activity: FileSaved(xmlString)
  Activity->>FileManager: saveXmlToDownloads(xmlString)
  FileManager-->>Activity: Result<String>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • avestaadfa
  • Daniel-ADFA

Poem

🐰 I hopped through bitmaps, badges, and files,
I drew tiny badges and counted the tiles.
I taught the app how to delete with a cheer,
Saved XML gently, and cleared badges near.
A carrot for code — refactor delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding visual hints (upload/delete badges) for image placeholders, which is the primary feature introduced across all modified files.
Description check ✅ Passed The description is directly related to the changeset. It explains the purpose (visual indicators for placeholders), details the key refactorings (DetectionVisualizer, XmlFileManager, DrawableImportHelper), and references the ticket.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ADFA-3972-image-placeholder-visuals-experimental

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt (1)

129-129: 💤 Low value

Remove debug log from production code.

Log.d("DetectionVisualizer", "Visualizing ${detections.size} detections") fires on every call to visualize(), which is triggered on every detection re-render.

🧹 Proposed fix
-        Log.d("DetectionVisualizer", "Visualizing ${detections.size} detections")
         return mutableBitmap
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt`
at line 129, The debug Log.d call in DetectionVisualizer.visualize() floods logs
on every re-render; remove the line Log.d("DetectionVisualizer", "Visualizing
${detections.size} detections") (or replace it with a
conditional/level-appropriate telemetry call) so production builds no longer
emit this debug message; update DetectionVisualizer.visualize() accordingly and
keep any necessary production logging at info/warn level or behind a debug flag.
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt (1)

53-67: 🏗️ Heavy lift

MediaStore.insert accumulates duplicate files on Android Q+ instead of overwriting.

On API 29 and above, MediaStore.insert won't overwrite files when an existing file already exists, but will add a new entry to the MediaStore collection using a slightly different name. Repeated exports will accumulate files such as testing_result.xml, testing_result (1).xml, etc. in Downloads. The pre-Q FileOutputStream path overwrites in place, so there is a behavioral inconsistency between API levels.

To match the overwrite behavior on Q+, query for an existing entry by DISPLAY_NAME first, delete it if found, and then insert the new record.

♻️ Suggested approach for overwrite-on-Q+
 `@RequiresApi`(Build.VERSION_CODES.Q)
 private fun saveUsingMediaStore(xmlString: String, fileName: String) {
     val resolver = context.contentResolver
+
+    // Delete any existing entry with the same name to avoid duplicates
+    resolver.query(
+        MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+        arrayOf(MediaStore.MediaColumns._ID),
+        "${MediaStore.MediaColumns.DISPLAY_NAME} = ?",
+        arrayOf(fileName),
+        null
+    )?.use { cursor ->
+        if (cursor.moveToFirst()) {
+            val id = cursor.getLong(0)
+            val existingUri = ContentUris.withAppendedId(
+                MediaStore.Downloads.EXTERNAL_CONTENT_URI, id
+            )
+            resolver.delete(existingUri, null, null)
+        }
+    }
+
     val contentValues = ContentValues().apply {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt`
around lines 53 - 67, saveUsingMediaStore currently always calls resolver.insert
which creates duplicate entries on API 29+; modify saveUsingMediaStore to first
query MediaStore.Downloads for existing rows with
MediaStore.MediaColumns.DISPLAY_NAME == fileName (use resolver.query on
MediaStore.Downloads.EXTERNAL_CONTENT_URI and selection on DISPLAY_NAME), delete
any found entries via resolver.delete(uri, null, null) (handle multiple matches
by deleting all), then call resolver.insert and openOutputStream as before so
the MediaStore path overwrites rather than accumulates duplicates; keep existing
IOException handling and ensure you reference the same symbols
(saveUsingMediaStore, resolver, MediaStore.Downloads.EXTERNAL_CONTENT_URI,
MediaStore.MediaColumns.DISPLAY_NAME) when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/ComputerVisionActivity.kt`:
- Around line 117-125: The UI update path skips calling
detectionVisualizer.visualize() when state.hasDetections is false, leaving stale
badge rectangles in DetectionVisualizer.deleteIconClickableAreas so
handleImageTap()'s getTappedDeleteIconId() can match old areas; fix by ensuring
the visualizer cache is cleared when detections disappear — either always call
detectionVisualizer.visualize(...) from updateUi() (pass an empty list/empty
detections and the current bitmap when state.hasDetections is false) or add and
call a clear method on DetectionVisualizer (e.g.,
clearDeleteIconClickableAreas()) from updateUi() when detections were removed so
getTappedDeleteIconId() cannot match stale rectangles.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt`:
- Around line 455-477: The current condition in removePlaceholderImage
incorrectly treats any Result.failure as success because exceptionOrNull() is
always an Exception; change the success check to use deletionResult.isSuccess
only, so state is only cleared on confirmed deletion; on failure (when
!deletionResult.isSuccess) do not update selectedImagesByPlaceholderId, send
ComputerVisionEffect.ShowError with the
deletionResult.exceptionOrNull()?.message (or a user-friendly message) and log
the exception from drawableImportHelper.deleteDrawable so failures are visible
for debugging; keep the _uiState.update call and
ComputerVisionEffect.ShowToast(R.string.msg_image_removed) only inside the
deletionResult.isSuccess branch.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt`:
- Line 31: The default filename "testing_result.xml" in
saveXmlToDownloads(xmlString: String, fileName: String = "testing_result.xml")
is a leftover test artifact and should be replaced with a descriptive default or
promoted to a constant; change the default parameter to a clearer name such as
"layout_result.xml" and/or extract it to a named constant (e.g.,
DEFAULT_XML_FILENAME) and update any usages and docs to reference that constant
for clarity and maintainability.

---

Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt`:
- Line 129: The debug Log.d call in DetectionVisualizer.visualize() floods logs
on every re-render; remove the line Log.d("DetectionVisualizer", "Visualizing
${detections.size} detections") (or replace it with a
conditional/level-appropriate telemetry call) so production builds no longer
emit this debug message; update DetectionVisualizer.visualize() accordingly and
keep any necessary production logging at info/warn level or behind a debug flag.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt`:
- Around line 53-67: saveUsingMediaStore currently always calls resolver.insert
which creates duplicate entries on API 29+; modify saveUsingMediaStore to first
query MediaStore.Downloads for existing rows with
MediaStore.MediaColumns.DISPLAY_NAME == fileName (use resolver.query on
MediaStore.Downloads.EXTERNAL_CONTENT_URI and selection on DISPLAY_NAME), delete
any found entries via resolver.delete(uri, null, null) (handle multiple matches
by deleting all), then call resolver.insert and openOutputStream as before so
the MediaStore path overwrites rather than accumulates duplicates; keep existing
IOException handling and ensure you reference the same symbols
(saveUsingMediaStore, resolver, MediaStore.Downloads.EXTERNAL_CONTENT_URI,
MediaStore.MediaColumns.DISPLAY_NAME) when making the change.
🪄 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: 2b9156d4-250f-43aa-9095-4a0e5a6295a9

📥 Commits

Reviewing files that changed from the base of the PR and between 13b45ee and e3c1649.

📒 Files selected for processing (9)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/data/repository/DrawableImportHelper.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/ui/ComputerVisionEvent.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/XmlFileManager.kt
  • cv-image-to-xml/src/main/res/drawable/ic_placeholder_delete.xml
  • cv-image-to-xml/src/main/res/drawable/ic_placeholder_upload.xml
  • cv-image-to-xml/src/main/res/values/strings.xml

@jatezzz jatezzz force-pushed the feat/ADFA-3972-image-placeholder-visuals-experimental branch from e3c1649 to 65a713c Compare May 11, 2026 13:36
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt (1)

219-219: 💤 Low value

Consider if alpha setting is necessary.

Setting alpha = 255 on every draw call might be redundant since the drawables are already mutated (lines 70, 76) and should retain their state. This is not a bug, but if the drawables are already fully opaque, this line could be removed for minor performance optimization.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt`
at line 219, The call setting iconDrawable.alpha = 255 on each draw is likely
redundant; inspect DetectionVisualizer.kt (look for the iconDrawable variable
and its mutate() calls around where draw icons are prepared, e.g., the mutate()
calls near lines ~70 and ~76) and remove the per-draw assignment of
iconDrawable.alpha = 255 if the drawable is already mutated and intended to be
fully opaque, ensuring no other code relies on resetting alpha there (or
alternatively move a single alpha initialization to the drawable setup path
instead of on every draw).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt`:
- Line 219: The call setting iconDrawable.alpha = 255 on each draw is likely
redundant; inspect DetectionVisualizer.kt (look for the iconDrawable variable
and its mutate() calls around where draw icons are prepared, e.g., the mutate()
calls near lines ~70 and ~76) and remove the per-draw assignment of
iconDrawable.alpha = 255 if the drawable is already mutated and intended to be
fully opaque, ensuring no other code relies on resetting alpha there (or
alternatively move a single alpha initialization to the drawable setup path
instead of on every draw).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b765b1e-51ad-4c8b-b28d-d6b8bbb2a006

📥 Commits

Reviewing files that changed from the base of the PR and between 65a713c and 6fdb6c4.

📒 Files selected for processing (1)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/DetectionVisualizer.kt

jatezzz added 3 commits May 11, 2026 12:43
Extract rendering and file management logic into dedicated helper classes.
…ionResult` conditional and change the layout result filename from `testing_result.xml` to `layout_result.xml`
@jatezzz jatezzz force-pushed the feat/ADFA-3972-image-placeholder-visuals-experimental branch from 6fdb6c4 to 2de2ad8 Compare May 11, 2026 17:43
@jatezzz jatezzz merged commit 853d4fc into stage May 11, 2026
2 checks passed
@jatezzz jatezzz deleted the feat/ADFA-3972-image-placeholder-visuals-experimental branch May 11, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants