Services/MenuService.cs

using System.Windows.Controls;
using WPFMenuItem = System.Windows.Controls.MenuItem;
using Hardcodet.Wpf.TaskbarNotification;
using System;
using System.Management.Automation;
using System.IO;
using System.Drawing;
using System.Windows;
 
namespace pscommander
{
    public class MenuService
    {
        private readonly TaskbarIcon _taskbarIcon;
        private readonly PowerShellService _powerShellService;
        private readonly CommanderEventProvider _commanderEventProvider;
 
        public MenuService(PowerShellService powerShellService, CommanderEventProvider commanderEventProvider)
        {
            _taskbarIcon = new TaskbarIcon();
            _powerShellService = powerShellService;
            _commanderEventProvider = commanderEventProvider;
        }
 
        public void UpdateToolbar(ToolbarIcon icon)
        {
            _taskbarIcon.Dispatcher.Invoke(() => {
 
                if (string.IsNullOrEmpty(icon.Text))
                {
                    _taskbarIcon.ToolTipText = "PSCommander";
                }
                else
                {
                    _taskbarIcon.ToolTipText = icon.Text;
                }
 
                if (string.IsNullOrWhiteSpace(icon.Icon))
                {
                    _taskbarIcon.Icon = LoadDefaultIcon();
                }
                else
                {
                    _taskbarIcon.Icon = Icon.ExtractAssociatedIcon(icon.Icon);
                }
 
                _taskbarIcon.ContextMenu = new ContextMenu();
                _taskbarIcon.PreviewTrayContextMenuOpen += (s, e) => {
                    _taskbarIcon.ContextMenu.Items.Clear();
 
                    if (icon.MenuItems != null)
                    {
                        foreach(var menuItem in icon.MenuItems)
                        {
                            AddMenuItem(_taskbarIcon.ContextMenu.Items, menuItem);
                        }
                    }
 
                    if (icon.LoadItems != null)
                    {
                        try
                        {
                            var menuItems = _powerShellService.Execute<MenuItem>(icon.LoadItems);
                            foreach(var menuItem in menuItems)
                            {
                                AddMenuItem(_taskbarIcon.ContextMenu.Items, menuItem);
                            }
                        }
                        catch (Exception ex)
                        {
                            ShowError(ex.Message);
                        }
                    }
 
                    if (!icon.HideConfig)
                    {
                        var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                        var path = Path.Combine(documents, "PSCommander", "config.ps1");
 
                        AddMenuItem(_taskbarIcon.ContextMenu.Items, new MenuItem {
                            Text = "Edit Config",
                            Action = CreateEditConfigAction(path)
                        });
                    }
 
                    if (!icon.HideExit)
                    {
                        AddMenuItem(_taskbarIcon.ContextMenu.Items, new MenuItem {
                            Text = "Exit",
                            Action = ScriptBlock.Create($"[System.Environment]::Exit(0)")
                        });
                    }
                };
                _taskbarIcon.MenuActivation = PopupActivationMode.RightClick;
            });
        }
 
        private static ScriptBlock CreateEditConfigAction(string path)
        {
            var escapedPath = EscapePowerShellSingleQuotedString(path);
            var script = $@"
$configPath = '{escapedPath}'
$code = Get-Command -Name code.cmd, code.exe, code -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
 
if ($code) {{
    Start-Process -FilePath $code.Source -ArgumentList @('-n', $configPath)
}}
else {{
    Start-Process -FilePath notepad.exe -ArgumentList @($configPath)
}}
";
 
            return ScriptBlock.Create(script);
        }
 
        private static string EscapePowerShellSingleQuotedString(string value)
        {
            return value.Replace("'", "''");
        }
 
        private static Icon LoadDefaultIcon()
        {
            var resourceInfo = Application.GetResourceStream(new Uri("pack://application:,,,/Resources/icon.ico"));
            if (resourceInfo == null)
            {
                throw new FileNotFoundException("The default tray icon resource could not be found.", "Resources/icon.ico");
            }
            using var icon = new Icon(resourceInfo.Stream);
            return (Icon)icon.Clone();
        }
 
        private void AddMenuItem(ItemCollection items, MenuItem item)
        {
            var wpfMenuItem = new WPFMenuItem();
            wpfMenuItem.Header = item.Text;
            wpfMenuItem.SubmenuOpened += (s, e) => {
                if (item.LoadChildren != null)
                {
                    wpfMenuItem.Items.Clear();
                    if (item.Children != null)
                    {
                        foreach(var menuItem in item.Children)
                        {
                            AddMenuItem(wpfMenuItem.Items, menuItem);
                        }
                    }
 
                    try
                    {
                        var menuItems = _powerShellService.Execute<MenuItem>(item.LoadChildren);
                        foreach(var menuItem in menuItems)
                        {
                            AddMenuItem(wpfMenuItem.Items, menuItem);
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowError(ex.Message);
                    }
                }
            };
            wpfMenuItem.Click += (s, e) => {
                e.Handled = true;
                if (item.Action == null) return;
 
                try
                {
                    _powerShellService.Execute(item.Action, item.ArgumentList);
                }
                catch (Exception ex)
                {
                    ShowError(ex.Message);
                }
            };
             
            items.Add(wpfMenuItem);
 
            if (item.Children != null)
            {
                foreach(var child in item.Children)
                {
                    AddMenuItem(wpfMenuItem.Items, child);
                }
            }
            else if (item.LoadChildren != null)
            {
                AddMenuItem(wpfMenuItem.Items, new MenuItem { Text = "Default" });
            }
        }
 
        public void ShowError(string error)
        {
            _commanderEventProvider.Error(error);
            _taskbarIcon.ShowBalloonTip("Error", error, BalloonIcon.Error);
        }
 
        public void ShowInfo(string info)
        {
            _taskbarIcon.ShowBalloonTip("Info", info, BalloonIcon.Info);
        }
    }
}