Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 81 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,107 @@
# android-resource-usage-tracker
# Android Resource Usage Tracker

![Build](https://github.com/dmitrish/android-resource-usage-tracker/workflows/Build/badge.svg)
[![Version](https://img.shields.io/jetbrains/plugin/v/MARKETPLACE_ID.svg)](https://plugins.jetbrains.com/plugin/MARKETPLACE_ID)
[![Downloads](https://img.shields.io/jetbrains/plugin/d/MARKETPLACE_ID.svg)](https://plugins.jetbrains.com/plugin/MARKETPLACE_ID)

## Template ToDo list
- [x] Create a new [IntelliJ Platform Plugin Template][template] project.
- [ ] Get familiar with the [template documentation][template].
- [ ] Adjust the [pluginGroup](./gradle.properties) and [pluginName](./gradle.properties), as well as the [id](./src/main/resources/META-INF/plugin.xml) and [sources package](./src/main/kotlin).
- [ ] Adjust the plugin description in `README` (see [Tips][docs:plugin-description])
- [ ] Review the [Legal Agreements](https://plugins.jetbrains.com/docs/marketplace/legal-agreements.html?from=IJPluginTemplate).
- [ ] [Publish a plugin manually](https://plugins.jetbrains.com/docs/intellij/publishing-plugin.html?from=IJPluginTemplate) for the first time.
- [ ] Set the `MARKETPLACE_ID` in the above README badges. You can obtain it once the plugin is published to JetBrains Marketplace.
- [ ] Set the [Plugin Signing](https://plugins.jetbrains.com/docs/intellij/plugin-signing.html?from=IJPluginTemplate) related [secrets](https://github.com/JetBrains/intellij-platform-plugin-template#environment-variables).
- [ ] Set the [Deployment Token](https://plugins.jetbrains.com/docs/marketplace/plugin-upload.html?from=IJPluginTemplate).
- [ ] Click the <kbd>Watch</kbd> button on the top of the [IntelliJ Platform Plugin Template][template] to be notified about releases containing new features and fixes.
- [ ] Configure the [CODECOV_TOKEN](https://docs.codecov.com/docs/quick-start) secret for automated test coverage reports on PRs

<!-- Plugin description -->
This Fancy IntelliJ Platform Plugin is going to be your implementation of the brilliant ideas that you have.
Track and visualize Android resource usage across your entire project with intuitive gutter icons and interactive popups.

**Features:**
- **Visual Usage Counters** - See at a glance how many times each resource is used with color-coded gutter icons
- **Interactive Click Navigation** - Click any usage counter to see all usages with code snippets and navigate directly to them
- **Cross-Module Search** - Finds usages across all modules in multi-module projects
- **AndroidManifest.xml Detection** - Detects theme and style references in manifest files
- **Smart Deduplication** - Uses PSI tree hashing to avoid duplicate results
- **Performance Optimized** - Word-based indexing for fast searches even in large projects
- **Supports All Resource Types** - Strings, colors, dimensions, styles, drawables, and more

**Perfect for:**
- Identifying unused resources for cleanup
- Understanding resource dependencies
- Refactoring with confidence
- Code reviews and audits
<!-- Plugin description end -->

This specific section is a source for the [plugin.xml](/src/main/resources/META-INF/plugin.xml) file which will be extracted by the [Gradle](/build.gradle.kts) during the build process.
## Screenshots

To keep everything working, do not remove `<!-- ... -->` sections.
<!-- Plugin description end -->
![Resource Usage Tracker in Action](https://via.placeholder.com/800x400?text=Add+Screenshot+Here)
*Gutter icons showing resource usage counts with interactive popup*

## Usage

1. Open any Android resource file (e.g., `res/values/strings.xml`, `res/values/colors.xml`)
2. Look for colored badges in the gutter next to each resource definition
3. Click on any badge to see:
- All usages across your project
- Code snippets showing context
- File paths and line numbers
4. Double-click any usage to navigate directly to that location

**Understanding the Badge Colors:**

| Color | Usage Count | Meaning | Action |
|-------|-------------|---------|--------|
| 🔴 Red | 0 | Unused resource | Safe to delete - consider cleanup |
| 🟢 Green | 1-4 | Normal usage | Standard resource, well-scoped |
| 🟠 Orange | 5+ | Heavily used | Core resource, refactor carefully |

## Supported Resource Types

- Strings (`<string>`)
- Colors (`<color>`)
- Dimensions (`<dimen>`)
- Styles and Themes (`<style>`)
- Drawables (`<drawable>`)
- Integers (`<integer>`)
- Booleans (`<bool>`)
- Arrays (`<array>`, `<string-array>`, `<integer-array>`)
- Plurals (`<plurals>`)
- IDs (`<id>`)

## Requirements

- Android Studio Arctic Fox (2020.3.1) or newer
- IntelliJ IDEA with Android plugin

## Installation

- Using the IDE built-in plugin system:
- **Using IDE built-in plugin system:**

<kbd>Settings/Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>Marketplace</kbd> > <kbd>Search for "android-resource-usage-tracker"</kbd> >
<kbd>Install</kbd>
<kbd>Settings/Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>Marketplace</kbd> > <kbd>Search for "Android Resource Usage Tracker"</kbd> > <kbd>Install</kbd>

- Using JetBrains Marketplace:
- **Using JetBrains Marketplace:**

Go to [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/MARKETPLACE_ID) and install it by clicking the <kbd>Install to ...</kbd> button in case your IDE is running.
Go to [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/coroutines) and install it by clicking the <kbd>Install to ...</kbd> button in case your IDE is running.

You can also download the [latest release](https://plugins.jetbrains.com/plugin/MARKETPLACE_ID/versions) from JetBrains Marketplace and install it manually using
You can also download the [latest release](https://plugins.jetbrains.com/plugin/coroutines/versions) from JetBrains Marketplace and install it manually using
<kbd>Settings/Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>⚙️</kbd> > <kbd>Install plugin from disk...</kbd>

- Manually:
- **Manually:**

Download the [latest release](https://github.com/dmitrish/android-resource-usage-tracker/releases/latest) and install it manually using
<kbd>Settings/Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>⚙️</kbd> > <kbd>Install plugin from disk...</kbd>

## Known Limitations

- Does not track resources used via reflection or dynamic resource loading
- Generated files (R.java, BuildConfig) are excluded from usage counts
- First-time indexing may take a moment in very large projects

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Support

If you encounter any issues or have feature requests, please [open an issue](https://github.com/dmitrish/android-resource-usage-tracker/issues) on GitHub.

---
Plugin based on the [IntelliJ Platform Plugin Template][template].

[template]: https://github.com/JetBrains/intellij-platform-plugin-template
[docs:plugin-description]: https://plugins.jetbrains.com/docs/intellij/plugin-user-experience.html#plugin-description-and-presentation
[docs:plugin-description]: https://plugins.jetbrains.com/docs/intellij/plugin-user-experience.html#plugin-description-and-presentation
Binary file added docs/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,6 @@ import javax.swing.border.EmptyBorder

class ResourceUsageLineMarkerProvider : LineMarkerProvider {

/*
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
if (element !is XmlTag) return null
if (element.name !in listOf("string", "color", "dimen", "style", "drawable", "integer", "bool", "array", "string-array", "integer-array", "plurals", "id")) {
return null
}

val resourceName = element.getAttributeValue("name") ?: return null
val count = UsageCounter.countUsages(element)

return LineMarkerInfo(
element,
element.textRange,
createUsageIcon(count),
{ "$count usage${if (count != 1) "s" else ""}" },
{ e, elt ->
if (count > 0) {
showUsagesPopup(e, elt as XmlTag, elt.project)
}
},
GutterIconRenderer.Alignment.RIGHT,
{ "$count usage${if (count != 1) "s" else ""}" }
)
}

*/

override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
// Only process the tag name identifier (leaf element), not the whole tag
if (element !is com.intellij.psi.xml.XmlToken) return null
Expand Down Expand Up @@ -94,6 +67,7 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {
{ "$count usage${if (count != 1) "s" else ""}" }
)
}

private fun createUsageIcon(count: Int): Icon {
return object : Icon {
override fun getIconWidth() = 21
Expand All @@ -104,9 +78,9 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)

val color = when {
count == 0 -> JBColor(Color(200, 200, 200), Gray._100)
count < 5 -> JBColor(Color(100, 180, 255), Color(80, 140, 200))
else -> JBColor(Color(100, 200, 100), Color(80, 160, 80))
count == 0 -> JBColor(Color(220, 80, 80), Color(180, 60, 60)) // Red - unused
count in 1..4 -> JBColor(Color(100, 200, 100), Color(80, 160, 80)) // Green - normal
else -> JBColor(Color(255, 165, 0), Color(220, 140, 0)) // Orange - heavily used
}

g2d.color = color
Expand Down Expand Up @@ -146,7 +120,7 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {

panel.add(titleLabel, BorderLayout.NORTH)

val usagesList = createUsagesList(usages, project)
val usagesList = createUsagesList(usages, project, popup)
val scrollPane = JScrollPane(usagesList).apply {
preferredSize = Dimension(600, minOf(300, usages.size * 60 + 20))
border = null
Expand All @@ -161,7 +135,6 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {
popup.setLocation(locationOnScreen.x + event.x + 10, locationOnScreen.y + event.y)

popup.isVisible = true
// popup.isFocusableWindowState = true
popup.requestFocus()

popup.addWindowFocusListener(object : java.awt.event.WindowFocusListener {
Expand All @@ -172,7 +145,7 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {
})
}

private fun createUsagesList(usages: List<ResourceUsage>, project: Project): JList<ResourceUsage> {
private fun createUsagesList(usages: List<ResourceUsage>, project: Project, popup: JWindow): JList<ResourceUsage> {
val listModel = DefaultListModel<ResourceUsage>()
usages.forEach { listModel.addElement(it) }

Expand All @@ -185,6 +158,9 @@ class ResourceUsageLineMarkerProvider : LineMarkerProvider {
if (e.clickCount == 2) {
val usage = selectedValue ?: return

// Dispose popup BEFORE navigating
popup.dispose()

// Use the full absolute path directly for navigation
val virtualFile = LocalFileSystem.getInstance().findFileByPath(usage.filePath)

Expand Down
26 changes: 23 additions & 3 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,29 @@
<name>Android Resource Usage Tracker</name>
<vendor>coroutines.com</vendor>
<description><![CDATA[
An IntelliJ IDEA / Android Studio plugin that enhances developer productivity
by providing real-time insights into how Android resources are used across your project.
]]></description>
Track and visualize Android resource usage across your project.

Features:
• Visual usage counters in the gutter for all Android resources (strings, colors, styles, etc.)
• Click to see all usages with code snippets
• Cross-module search - finds usages in all modules
• AndroidManifest.xml theme detection
• Smart deduplication using PSI tree hashing
• Performance optimized with word-based indexing
]]></description>

<change-notes><![CDATA[
<h3>Version 0.0.1</h3>
<ul>
<li>Initial release</li>
<li>Usage tracking for strings, colors, dimensions, styles, and more</li>
<li>Cross-module search support</li>
<li>Interactive popup with navigation</li>
</ul>
]]></change-notes>

<!-- Add compatibility range -->
<idea-version since-build="233.0" until-build="243.*"/>
<depends>com.intellij.modules.platform</depends>
<depends>org.jetbrains.android</depends>

Expand Down
Loading