Skip to content

Create ConfigurableTrayService base class for reusable tray service logic #2

Description

@Olbrasoft

Problem

Currently, each project (PushToTalk, VirtualAssistant) needs to create its own wrapper service around TrayIconManager:

  • PushToTalkTrayService - handles main icon, animated icon, menu events
  • VirtualAssistantTrayService - handles single icon with mute state, different menu

While each project has unique requirements (different events, state, menu structure), there's common boilerplate code for:

  • Icon creation and rendering
  • Basic lifecycle management
  • Common patterns for menu building

Proposed Solution

Create an abstract ConfigurableTrayService base class in the NuGet package that provides:

public abstract class ConfigurableTrayService : IDisposable
{
    protected readonly TrayIconManager _manager;
    protected readonly ILogger _logger;
    protected ITrayIcon? _mainIcon;
    
    protected ConfigurableTrayService(ILogger logger, TrayIconManager manager)
    {
        _logger = logger;
        _manager = manager;
    }
    
    // Shared logic
    protected void CreateIcon(string iconPath, string tooltip, string id)
    {
        // Common icon creation logic
    }
    
    // Project-specific overrides
    protected abstract void BuildMenu(ITrayIcon icon);
    protected abstract void OnIconClicked();
    
    public abstract void Dispose();
}

Then projects only need to implement their specific logic:

public class PushToTalkTrayService : ConfigurableTrayService
{
    public event Action? OnQuitRequested;
    
    protected override void BuildMenu(ITrayIcon icon)
    {
        // PushToTalk-specific menu items
    }
    
    protected override void OnIconClicked()
    {
        // PushToTalk-specific click behavior
    }
}

Benefits

  • Less boilerplate: Common icon creation/rendering logic in base class
  • Flexibility: Each project can still customize events, state, menu structure
  • Maintainability: Bug fixes in common logic benefit all projects
  • Testability: Base class logic can be tested once

Alternatives Considered

Fully generic wrapper with configuration: Too complex - would need dozens of parameters/callbacks for different events, menu structures, state management. Current approach (base class with abstract methods) provides better balance.

Implementation Tasks

  • Design base class API
  • Implement ConfigurableTrayService in SystemTray.Linux
  • Migrate PushToTalkTrayService to inherit from base class
  • Migrate VirtualAssistantTrayService to inherit from base class
  • Update documentation with usage examples
  • Publish new NuGet version (1.1.0?)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions