Feature: Dynamic Icons for File Groups#43
Conversation
Implement feature request from issue #31 to allow users to customize icons for file groups beyond automatic pattern-based matching. Changes: - Add customIconPath field to ProjectFileGroup data class - Create FileGroupIconOption enum with 18 predefined icon choices - Add icon ComboBox to ProjectFileGroupDialog with visual icon picker - Update ProjectFileGroupNode to prioritize custom icons over auto-detection - Add localization for icon picker label - Preserve customIconPath in settings persistence Users can now select from icons including Folder, Package, Module, Config Folder, Settings, Resources, and more, or use "Auto" for pattern-based detection. Resolves #31 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR implements custom icon selection for file groups in the Android project view plugin. Users can now manually choose icons from IntelliJ's icon set when editing file groups, with custom selections stored and applied to the project tree view. Changes
Sequence DiagramsequenceDiagram
actor User
participant Dialog as ProjectFileGroupDialog
participant Settings as AndroidViewSettings
participant Node as ProjectFileGroupNode
participant Renderer as Project Tree View
User->>Dialog: Open/Edit file group
Dialog->>Dialog: Display icon picker (FileGroupIconOption)
User->>Dialog: Select custom icon
Dialog->>Settings: Save ProjectFileGroup with customIconPath
Settings->>Node: Update node for group
Node->>Node: Resolve icon via getIconFromPath(customIconPath)
Node->>Renderer: Render with custom icon
Renderer->>User: Display custom icon in tree
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
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 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/kotlin/com/z8dn/plugins/a2pt/nodes/ProjectFileGroupNode.kt (1)
67-125: 🛠️ Refactor suggestion | 🟠 MajorReplace
getIconFromPathwithFileGroupIconOption.fromIconPath()to eliminate duplication and fix detekt warnings.This 27-line
when-expression duplicates the mapping already defined inFileGroupIconOption. The comment on line 101 ("use reflection") is also misleading — no reflection is used. Additionally, thetry-catcharound a purewhen-expression is unnecessary (detekt:TooGenericExceptionCaught,SwallowedException).♻️ Proposed refactor
private fun getGroupIcon(): Icon { // Check if a custom icon is set if (fileGroup.customIconPath != null) { - return getIconFromPath(fileGroup.customIconPath!!) + return FileGroupIconOption.fromIconPath(fileGroup.customIconPath).icon } if (fileGroup.patterns.size == 1) {And remove the entire
getIconFromPathfunction (lines 95–125). Add the import:import com.z8dn.plugins.a2pt.settings.FileGroupIconOption
🤖 Fix all issues with AI agents
In `@src/main/kotlin/com/z8dn/plugins/a2pt/settings/FileGroupIconOption.kt`:
- Around line 10-43: ProjectFileGroupNode.getIconFromPath duplicates the
iconPath→Icon mapping already centralized in FileGroupIconOption; replace that
logic with FileGroupIconOption.fromIconPath(iconPath).icon so the enum is the
single source of truth. Update ProjectFileGroupNode.getIconFromPath to call
FileGroupIconOption.fromIconPath(iconPath) and return its .icon (handle
null/unknown by relying on fromIconPath returning AUTO). Remove the duplicated
mapping entries in ProjectFileGroupNode to avoid drift and ensure any future
icon additions are made only in FileGroupIconOption.
| enum class FileGroupIconOption( | ||
| val displayName: String, | ||
| val iconPath: String?, | ||
| val icon: Icon | ||
| ) { | ||
| AUTO("Auto (based on patterns)", null, AllIcons.FileTypes.Any_type), | ||
| FOLDER("Folder", "AllIcons.Nodes.Folder", AllIcons.Nodes.Folder), | ||
| PACKAGE("Package", "AllIcons.Nodes.Package", AllIcons.Nodes.Package), | ||
| MODULE("Module", "AllIcons.Nodes.Module", AllIcons.Nodes.Module), | ||
| CONFIG_FOLDER("Config Folder", "AllIcons.Nodes.ConfigFolder", AllIcons.Nodes.ConfigFolder), | ||
| DATA_TABLES("Data Tables", "AllIcons.Nodes.DataTables", AllIcons.Nodes.DataTables), | ||
| RESOURCES("Resources", "AllIcons.Nodes.ResourceBundle", AllIcons.Nodes.ResourceBundle), | ||
| WEB_FOLDER("Web Folder", "AllIcons.Nodes.WebFolder", AllIcons.Nodes.WebFolder), | ||
| SETTINGS("Settings", "AllIcons.General.Settings", AllIcons.General.Settings), | ||
| GEAR("Gear", "AllIcons.General.GearPlain", AllIcons.General.GearPlain), | ||
| LIST_FILES("List Files", "AllIcons.Actions.ListFiles", AllIcons.Actions.ListFiles), | ||
| GROUP_BY("Group By", "AllIcons.Actions.GroupBy", AllIcons.Actions.GroupBy), | ||
| COPY("Copy", "AllIcons.Actions.Copy", AllIcons.Actions.Copy), | ||
| EDIT("Edit", "AllIcons.Actions.Edit", AllIcons.Actions.Edit), | ||
| CONFIG("Config File", "AllIcons.FileTypes.Config", AllIcons.FileTypes.Config), | ||
| TEXT("Text File", "AllIcons.FileTypes.Text", AllIcons.FileTypes.Text), | ||
| PROPERTIES("Properties", "AllIcons.FileTypes.Properties", AllIcons.FileTypes.Properties), | ||
| ARCHIVE("Archive", "AllIcons.FileTypes.Archive", AllIcons.FileTypes.Archive); | ||
|
|
||
| companion object { | ||
| /** | ||
| * Finds the IconOption that matches the given icon path. | ||
| * Returns AUTO if no match is found. | ||
| */ | ||
| fun fromIconPath(iconPath: String?): FileGroupIconOption { | ||
| if (iconPath == null) return AUTO | ||
| return entries.find { it.iconPath == iconPath } ?: AUTO | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Enum is well-structured, but the icon-path-to-Icon mapping is duplicated.
ProjectFileGroupNode.getIconFromPath() manually duplicates the same path→icon mapping that this enum already encapsulates. ProjectFileGroupNode should use FileGroupIconOption.fromIconPath(iconPath).icon instead, keeping this enum as the single source of truth.
This avoids the risk of the two mappings drifting out of sync when icons are added or removed.
🤖 Prompt for AI Agents
In `@src/main/kotlin/com/z8dn/plugins/a2pt/settings/FileGroupIconOption.kt` around
lines 10 - 43, ProjectFileGroupNode.getIconFromPath duplicates the iconPath→Icon
mapping already centralized in FileGroupIconOption; replace that logic with
FileGroupIconOption.fromIconPath(iconPath).icon so the enum is the single source
of truth. Update ProjectFileGroupNode.getIconFromPath to call
FileGroupIconOption.fromIconPath(iconPath) and return its .icon (handle
null/unknown by relying on fromIconPath returning AUTO). Remove the duplicated
mapping entries in ProjectFileGroupNode to avoid drift and ensure any future
icon additions are made only in FileGroupIconOption.
Qodana for JVMIt seems all right 👌 No new problems were found according to the checks applied ☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
Summary
Implements feature request from issue #31 to allow users to customize icons for file groups beyond automatic pattern-based matching.
Changes
customIconPathfield toProjectFileGroupdata class for storing custom icon selectionsFileGroupIconOptionenum with 18 predefined icon choices across categories:ProjectFileGroupDialogwith custom renderer showing icon + labelProjectFileGroupNodeto prioritize custom icons over auto-detectioncustomIconPathin settings persistence (apply/reset methods)User Experience
Users can now:
Example Use Case
A user with an "Infrastructure" group containing config files can now assign a "Settings" or "Config Folder" icon to make the group visually distinct in the project view.
Testing
Screenshots
The icon picker appears in the Edit File Group dialog between "Group name" and "File patterns" fields, showing icons visually in a dropdown.
Resolves #31
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes