Skip to content

Feature: Dynamic Icons for File Groups#43

Open
z8dn wants to merge 1 commit into
mainfrom
feature/dynamic-file-group-icons
Open

Feature: Dynamic Icons for File Groups#43
z8dn wants to merge 1 commit into
mainfrom
feature/dynamic-file-group-icons

Conversation

@z8dn
Copy link
Copy Markdown
Owner

@z8dn z8dn commented Feb 10, 2026

Summary

Implements 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 for storing custom icon selections
  • Create FileGroupIconOption enum with 18 predefined icon choices across categories:
    • Nodes: Folder, Package, Module, ConfigFolder, DataTables, ResourceBundle, WebFolder
    • Actions: ListFiles, GroupBy, Copy, Edit
    • General: Settings, GearPlain
    • FileTypes: Config, Text, Properties, Archive
  • Add icon ComboBox to ProjectFileGroupDialog with custom renderer showing icon + label
  • Update ProjectFileGroupNode to prioritize custom icons over auto-detection
  • Add localization for icon picker UI elements
  • Preserve customIconPath in settings persistence (apply/reset methods)

User Experience

Users can now:

  • Select a custom icon when creating or editing file groups
  • Choose from 18 visual icon options in a dropdown
  • Use "Auto (based on patterns)" to maintain current auto-detection behavior
  • See icons displayed alongside labels for easy selection

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

  • ✅ Project builds successfully with no errors
  • ✅ Backward compatible - existing groups without custom icons continue using auto-detection
  • ✅ Icon selection persists correctly in settings

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

  • New Features
    • Custom icon support for file groups: Users can now select custom icons for project file groups through an intuitive dropdown selector in the file group configuration dialog, enabling better visual organization of project structure.

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>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Core Data Model
src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettings.kt
Added customIconPath: String? property to ProjectFileGroup data class to store user-selected custom icon paths.
Icon Options Definition
src/main/kotlin/com/z8dn/plugins/a2pt/settings/FileGroupIconOption.kt
New public enum FileGroupIconOption with displayName, iconPath, and Icon references for available options; includes fromIconPath() companion utility to resolve enum values by path.
Dialog UI
src/main/kotlin/com/z8dn/plugins/a2pt/settings/ProjectFileGroupDialog.kt
Added icon picker ComboBox<FileGroupIconOption> with custom renderer to the dialog; passes selected customIconPath when creating ProjectFileGroup instances.
Node Rendering
src/main/kotlin/com/z8dn/plugins/a2pt/nodes/ProjectFileGroupNode.kt
Updated getGroupIcon() to prioritize custom icon via new getIconFromPath() helper; maps stored icon paths to actual icons with fallback to folder icon on unknown paths.
Settings Handling
src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettingsConfigurable.kt
Updated apply() and reset() methods to pass customIconPath argument when reconstructing ProjectFileGroup instances from UI model.
Localization
src/main/resources/messages/AndroidViewBundle.properties
Added message key dialog.ProjectFileGroup.Icon.text=Icon: for the icon picker label.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #16: Modifies ProjectFileGroupNode icon-selection logic; this PR extends that logic with custom icon path support and proper icon resolution.
  • PR #28: Updates ProjectFileGroup data class/constructors; this PR adds the customIconPath parameter to that constructor signature.

Poem

🐰 In the forest of folders so green and so bright,
We've painted with icons—a marvelous sight!
Custom colors for groups, a rabbit's delight,
Now users can choose what looks just right! 🎨✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Feature: Dynamic Icons for File Groups' accurately reflects the main objective of adding customizable icons for file groups.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #31: added customIconPath field, created FileGroupIconOption enum with predefined icons, integrated icon picker in ProjectFileGroupDialog, updated ProjectFileGroupNode to prioritize custom icons, and ensured persistence.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing issue #31's requirements for dynamic file group icons; no extraneous modifications detected.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/dynamic-file-group-icons

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

@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: 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 | 🟠 Major

Replace getIconFromPath with FileGroupIconOption.fromIconPath() to eliminate duplication and fix detekt warnings.

This 27-line when-expression duplicates the mapping already defined in FileGroupIconOption. The comment on line 101 ("use reflection") is also misleading — no reflection is used. Additionally, the try-catch around a pure when-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 getIconFromPath function (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.

Comment on lines +10 to +43
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
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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.

@github-actions
Copy link
Copy Markdown

Qodana for JVM

It seems all right 👌

No new problems were found according to the checks applied

☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

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.

Feature: Dynamic Icons for File Groups

1 participant