Skip to content

refactor: extract IconLoader utility to eliminate icon loading duplication#172

Draft
Copilot wants to merge 2 commits into
mainfrom
copilot/refactor-icon-loading-pattern
Draft

refactor: extract IconLoader utility to eliminate icon loading duplication#172
Copilot wants to merge 2 commits into
mainfrom
copilot/refactor-icon-loading-pattern

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

Icon loading logic (path construction, File.Exists check, error handling, fallback) was duplicated across three files, with TaskbarBadgeManager additionally using a hardcoded "res" string instead of Constants.IconResourcePath.

Changes

  • New src/IconLoader.cs — static utility centralizing all icon loading:

    • TryLoadDefault(fileName)Icon? — loads at default size (preserves multi-resolution ICO behavior)
    • TryLoad(fileName, size)Icon? — loads at specific pixel size, returns null on miss/failure
    • LoadWithFallback(fileName, size, fallbackFactory) — thin wrapper over TryLoad with non-null guarantee
    • CreateIconFromBitmap(bitmap)GetHicon() + Clone() + DestroyIcon() to avoid GDI handle leak
  • MainWindow.cs — replaced manual try/catch with IconLoader.TryLoadDefault

  • SystemTrayManager.csCreateCustomIcon uses LoadWithFallback; fallback bitmap-to-icon conversion goes through CreateIconFromBitmap to properly release the HICON handle

  • TaskbarBadgeManager.csDrawBaseIcon uses TryLoad; eliminates hardcoded "res" path; fallback draws gradient directly to avoid GetHicon() roundtrip

// Before: duplicated in 3 places, hardcoded paths, GDI leaks in fallback
var iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "res", "app_icon.ico");
if (File.Exists(iconPath)) { ... } else { Logger.LogWarning(...); DrawFallbackIcon(graphics); }

// After
var baseIcon = IconLoader.TryLoad(Constants.AppIconFileName, Constants.TaskbarIconSize);
if (baseIcon != null) { using (baseIcon) { ... } } else { DrawFallbackIcon(graphics); }
Original prompt

This section details on the original issue you should resolve

<issue_title>Duplicate Code: Icon Loading with Fallback Pattern in MainWindow, SystemTrayManager, TaskbarBadgeManager</issue_title>
<issue_description>Analysis of commit 0888461

Assignee: @copilot

Summary

The icon loading logic (path construction → File.Exists check → load icon → fallback on failure) is duplicated across three files with near-identical structure, each independently handling the app_icon.ico file loading and error/fallback scenarios.

Duplication Details

Pattern: Icon File Loading with Fallback

  • Severity: High

  • Occurrences: 3 instances across 3 files

  • Locations:

    • src/MainWindow.cs (lines 33–44)
    • src/SystemTrayManager.cs (lines 212–255)
    • src/TaskbarBadgeManager.cs (lines 168–188)
  • Code Sample (representative from each file):

// MainWindow.cs
try
{
    var iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
        Constants.IconResourcePath, Constants.AppIconFileName);
    if (File.Exists(iconPath))
    {
        Icon = new Icon(iconPath);
    }
}
catch (Exception ex)
{
    Logger.LogError("Failed to load application icon", ex);
}

// TaskbarBadgeManager.cs — near-identical, different size param
var iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "res", "app_icon.ico");
if (File.Exists(iconPath))
{
    using var baseIcon = new Icon(iconPath, 32, 32);
}
else
{
    Logger.LogWarning("app_icon.ico not found...");
    DrawFallbackIcon(graphics);
}

// SystemTrayManager.cs — near-identical, uses size variable + gradient fallback
var iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
    Constants.IconResourcePath, Constants.AppIconFileName);
if (File.Exists(iconPath))
{
    var icon = new Icon(iconPath, size, size);
}
else
{
    Logger.LogWarning("app_icon.ico not found...");
    // creates gradient bitmap fallback
}

Impact Analysis

  • Maintainability: The icon file path is partially hardcoded ("res") in TaskbarBadgeManager.cs instead of using Constants.IconResourcePath, creating inconsistency risk.
  • Bug Risk: Any change to icon loading behavior (e.g., new format support, different fallback) must be replicated in three places — high risk of divergence.
  • Code Bloat: ~30–40 lines of near-identical logic exist across three files that could be consolidated into a single utility.

Refactoring Recommendations

  1. Extract IconLoader utility class

    • Create: src/IconLoader.cs
    • Add method: public static Icon LoadWithFallback(string fileName, int size, Func(Icon) fallbackFactory)
    • Centralizes path construction (Path.Combine(BaseDirectory, Constants.IconResourcePath, fileName)), existence check, and error logging
    • Estimated effort: Low (1–2 hours)
    • Benefits: Single place to update icon loading; consistent fallback behavior; eliminates hardcoded path in TaskbarBadgeManager
  2. Fix hardcoded path in TaskbarBadgeManager.cs

    • Replace "res" with Constants.IconResourcePath immediately (independent of refactor)

Implementation Checklist

  • Review duplication findings
  • Fix hardcoded "res" path in TaskbarBadgeManager.cs to use Constants.IconResourcePath
  • Create src/IconLoader.cs utility class with LoadWithFallback method
  • Refactor MainWindow.cs to use IconLoader
  • Refactor SystemTrayManager.cs to use IconLoader
  • Refactor TaskbarBadgeManager.cs to use IconLoader
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 21 .cs files
  • Detection Method: Serena semantic code analysis
  • Commit: 0888461
  • Analysis Date: 2026-03-21

Generated by Duplicate Code Detector ·

To install this agentic workflow, run

gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619

Comments on the Issue (you are @copilot in this section)


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Copilot AI changed the title [WIP] Refactor duplicated icon loading logic with fallback refactor: extract IconLoader utility to eliminate icon loading duplication Mar 25, 2026
Copilot AI requested a review from sunzhuoshi March 25, 2026 11:05
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.

Duplicate Code: Icon Loading with Fallback Pattern in MainWindow, SystemTrayManager, TaskbarBadgeManager

2 participants