Skip to content

Update Context Menu Item for tray app on-the-fly. #270

@Tum4ik

Description

@Tum4ik

In my case it is related to the application localization, but it could be also useful for some other scenarios (like change item visibility or enable/disable item).

Currently I have this Desktoper class to bring the app to the desktop.

using System;
using System.Globalization;
using System.IO;
using System.Linq;
using ElectronNET.API;
using ElectronNET.API.Entities;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Tum4ik.RemoteControl.Server.Services;
using Tum4ik.RemoteControl.Server.Services.MQTT.MqttServer;

namespace Tum4ik.RemoteControl.Server.Desktop
{
  /// <inheritdoc />
  public class Desktoper : IDesktoper
  {
    private const string TrayRunIcon = "Desktop/icons/tray-run-icon.png";
    private const string TrayStopIcon = "Desktop/icons/tray-stop-icon.png";

    private readonly IServiceProvider _serviceProvider;
    private readonly IHostingEnvironment _env;
    private readonly IStringLocalizer<Desktoper> _localizer;
    private readonly IMqttServerService _mqttServerService;

    private BrowserWindow _settingsWindow;
    private readonly MenuItem[] _menuItems;

    public Desktoper(IServiceProvider serviceProvider,
                     IHostingEnvironment env,
                     IStringLocalizer<Desktoper> localizer,
                     IMqttServerService mqttServerService)
    {
      _serviceProvider = serviceProvider;
      _env = env;
      _localizer = localizer;
      _mqttServerService = mqttServerService;

      _menuItems = CreateMenuItems();
    }


    private MenuItem _runServerMenuItem;
    private MenuItem _stopServerMenuItem;
    private MenuItem _settingsMenuItem;
    private MenuItem _aboutMenuItem;
    private MenuItem _exitMenuItem;
    private readonly Func<IStringLocalizer, string> _runServerMenuItemLabelFunc = localizer => localizer["Run Server"];
    private readonly Func<IStringLocalizer, string> _stopServerMenuItemLabelFunc = localizer => localizer["Stop Server"];
    private readonly Func<IStringLocalizer, string> _settingsMenuItemLabelFunc = localizer => localizer["Settings"];
    private readonly Func<IStringLocalizer, string> _aboutMenuItemLabelFunc = localizer => localizer["About"];
    private readonly Func<IStringLocalizer, string> _exitMenuItemLabelFunc = localizer => localizer["Exit"];


    private MenuItem[] CreateMenuItems()
    {
      var trayMenuRunIcon = Path.Combine(_env.ContentRootPath, "Desktop/icons/tray-menu-run-icon.png");
      var trayMenuStopIcon = Path.Combine(_env.ContentRootPath, "Desktop/icons/tray-menu-stop-icon.png");
      var trayMenuSettingIcon = Path.Combine(_env.ContentRootPath, "Desktop/icons/tray-menu-settings-icon.png");
      var trayMenuAboutIcon = Path.Combine(_env.ContentRootPath, "Desktop/icons/tray-menu-about-icon.png");
      var trayMenuExitIcon = Path.Combine(_env.ContentRootPath, "Desktop/icons/tray-menu-exit-icon.png");

      var settingsWindowOptions = new BrowserWindowOptions
      {
        MinWidth = 800,
        MinHeight = 400,
        Width = 800,
        Height = 400,
        Frame = false,
        Icon = trayMenuSettingIcon,
        //        BackgroundColor = "#FF080F17",
        Fullscreenable = false,
        Center = true
      };

      _runServerMenuItem = new MenuItem
      {
        Label = _runServerMenuItemLabelFunc(_localizer),
        Icon = trayMenuRunIcon
      };
      _stopServerMenuItem = new MenuItem
      {
        Label = _stopServerMenuItemLabelFunc(_localizer),
        Icon = trayMenuStopIcon,
        Visible = false,
        Enabled = false
      };
      _runServerMenuItem.Click = async () =>
      {
        await _mqttServerService.StartAsync();
        _stopServerMenuItem.Visible = true;
        _stopServerMenuItem.Enabled = true;
        _runServerMenuItem.Visible = false;
        _runServerMenuItem.Enabled = false;
        Electron.Tray.SetImage(Path.Combine(_env.ContentRootPath, TrayRunIcon));
      };
      _stopServerMenuItem.Click = async () =>
      {
        await _mqttServerService.StopAsync();
        _runServerMenuItem.Visible = true;
        _runServerMenuItem.Enabled = true;
        _stopServerMenuItem.Visible = false;
        _stopServerMenuItem.Enabled = false;
        Electron.Tray.SetImage(Path.Combine(_env.ContentRootPath, TrayStopIcon));
      };
      _settingsMenuItem = new MenuItem
      {
        Label = _settingsMenuItemLabelFunc(_localizer),
        Icon = trayMenuSettingIcon,
        Click = async () =>
        {
          _settingsWindow = await Electron.WindowManager.CreateWindowAsync(settingsWindowOptions);
          _settingsWindow.Center();
        }
      };
      _aboutMenuItem = new MenuItem
      {
        Label = _aboutMenuItemLabelFunc(_localizer),
        Icon = trayMenuAboutIcon
      };
      _exitMenuItem = new MenuItem
      {
        Label = _exitMenuItemLabelFunc(_localizer),
        Icon = trayMenuExitIcon,
        Click = () => Electron.App.Quit()
      };
      var menuItems = new[]
      {
        _runServerMenuItem,
        _stopServerMenuItem,
        _settingsMenuItem,
        _aboutMenuItem,
        new MenuItem
        {
          Type = MenuType.separator
        },
        _exitMenuItem
      };

      return menuItems;
    }


    public void Desktopize()
    {
      var culture = GetCultureFromDb();
      UpdateMenuItems(culture);
      Electron.WindowManager.IsQuitOnWindowAllClosed = false;
      Electron.Tray.Show(TrayStopIcon, _menuItems);
    }


    public void CloseSettingsWindow()
    {
      _settingsWindow?.Close();
    }


    public void UpdateCulture(string culture)
    {
      UpdateMenuItems(culture);
      Electron.Tray.Destroy();
      Electron.Tray.Show(TrayStopIcon, _menuItems);
    }


    private void UpdateMenuItems(string culture)
    {
      var cultureInfo = new CultureInfo(culture);
      var localizer = _localizer.WithCulture(cultureInfo);
      _runServerMenuItem.Label = _runServerMenuItemLabelFunc(localizer);
      _stopServerMenuItem.Label = _stopServerMenuItemLabelFunc(localizer);
      _settingsMenuItem.Label = _settingsMenuItemLabelFunc(localizer);
      _aboutMenuItem.Label = _aboutMenuItemLabelFunc(localizer);
      _exitMenuItem.Label = _exitMenuItemLabelFunc(localizer);
    }


    private string GetCultureFromDb()
    {
      var database = _serviceProvider.CreateScope().ServiceProvider.GetService<DatabaseService>();
      var settings = database.Settings.FirstOrDefault();
      return settings?.Language ?? "en-US";
    }
  }
}

The Desktopize method is called from Startup Configure method.
The public UpdateCulture method is called from the settings controller when the culture is changed.
So I do this trick: destroy tray and then create it again with updated menu items. I guess it will be very useful to have such functionality, for example

Electron.Tray.UpdateMenuItem("menu_item_id", menuItem => 
{
  menuItem.Label = "changed_label",
  Enabled = false,
  Click = () => SomeNewBehavior()
});

Thanks!

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions