mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-09 18:36:27 +00:00
UI - Add a monochrome tray icon option
- New "Monochrome tray icon" toggle under General settings - Shows a black or white icon matching the light or dark mode of the system tray - On Windows the color follows the taskbar (Windows mode), which can differ from the app mode - On Linux the color follows the system's light or dark mode - On macOS the icon is a template icon, so the menu bar colors it itself - Icons come in 16 to 256px, including the sizes used for high-DPI tray scaling Based on the idea and work in #867 by ArthurGamerHD.
This commit is contained in:
1 parent
5ddd50b4a8
commit
7574ad4ad6
13 files changed
+157
-3
No files matched your search
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<TrayIcon.Icons>
|
<TrayIcon.Icons>
|
||||||
<TrayIcons>
|
<TrayIcons>
|
||||||
<TrayIcon Icon="avares://Artemis.UI/Assets/Images/Logo/application.ico" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
<TrayIcon Icon="{CompiledBinding TrayIcon}" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<TrayIcon.Icons>
|
<TrayIcon.Icons>
|
||||||
<TrayIcons>
|
<TrayIcons>
|
||||||
<TrayIcon Icon="avares://Artemis.UI/Assets/Images/Logo/application.ico" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
<TrayIcon Icon="{CompiledBinding TrayIcon}" MacOSProperties.IsTemplateIcon="{CompiledBinding MonochromeTrayIcon}" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<TrayIcon.Icons>
|
<TrayIcon.Icons>
|
||||||
<TrayIcons>
|
<TrayIcons>
|
||||||
<TrayIcon Icon="avares://Artemis.UI/Assets/Images/Logo/application.ico" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
<TrayIcon Icon="{CompiledBinding TrayIcon}" ToolTipText="Artemis" Command="{CompiledBinding OpenScreen}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Artemis.Core.Providers;
|
using Artemis.Core.Providers;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Services.Tray;
|
||||||
using Artemis.UI.Services.Updating;
|
using Artemis.UI.Services.Updating;
|
||||||
using Artemis.UI.Shared.Providers;
|
using Artemis.UI.Shared.Providers;
|
||||||
using Artemis.UI.Windows.Providers;
|
using Artemis.UI.Windows.Providers;
|
||||||
@@ -25,5 +26,6 @@ public static class UIContainerExtensions
|
|||||||
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
|
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
|
||||||
container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>();
|
container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>();
|
||||||
container.Register<IProtocolProvider, ProtocolProvider>();
|
container.Register<IProtocolProvider, ProtocolProvider>();
|
||||||
|
container.Register<ITrayThemeProvider, WindowsTrayThemeProvider>(Reuse.Singleton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.UI.Services.Tray;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Windows.Providers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the light or dark mode of the Windows taskbar, which can differ from the app mode Avalonia reports.
|
||||||
|
/// </summary>
|
||||||
|
public class WindowsTrayThemeProvider : ITrayThemeProvider
|
||||||
|
{
|
||||||
|
private const string PersonalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WindowsTrayThemeProvider" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public WindowsTrayThemeProvider(ILogger logger)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SystemEvents.UserPreferenceChanged += SystemEventsOnUserPreferenceChanged;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Warning(e, "Could not subscribe to system events, the tray icon won't follow changes to the taskbar color");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsTrayDark
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Versions of Windows without the setting only have a dark taskbar
|
||||||
|
using RegistryKey? key = Registry.CurrentUser.OpenSubKey(PersonalizeKey);
|
||||||
|
return key?.GetValue("SystemUsesLightTheme") is not 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler? TrayThemeChanged;
|
||||||
|
|
||||||
|
private void SystemEventsOnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Category == UserPreferenceCategory.General)
|
||||||
|
TrayThemeChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
@@ -4,6 +4,7 @@ using Artemis.UI.DryIoc.InstanceProviders;
|
|||||||
using Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
using Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
using Artemis.UI.Screens.VisualScripting;
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
|
using Artemis.UI.Services.Tray;
|
||||||
using Artemis.UI.Services.Updating;
|
using Artemis.UI.Services.Updating;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.NodeEditor;
|
using Artemis.UI.Shared.Services.NodeEditor;
|
||||||
@@ -33,6 +34,7 @@ public static class ContainerExtensions
|
|||||||
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
||||||
container.Register<IPropertyVmFactory, PropertyVmFactory>(Reuse.Singleton);
|
container.Register<IPropertyVmFactory, PropertyVmFactory>(Reuse.Singleton);
|
||||||
container.Register<IUpdateNotificationProvider, BasicUpdateNotificationProvider>();
|
container.Register<IUpdateNotificationProvider, BasicUpdateNotificationProvider>();
|
||||||
|
container.Register<ITrayThemeProvider, BasicTrayThemeProvider>(Reuse.Singleton);
|
||||||
|
|
||||||
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IArtemisUIService>(), Reuse.Singleton);
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IArtemisUIService>(), Reuse.Singleton);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Artemis.Core.Services;
|
|||||||
using Artemis.UI.Models;
|
using Artemis.UI.Models;
|
||||||
using Artemis.UI.Screens.Sidebar;
|
using Artemis.UI.Screens.Sidebar;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
|
using Artemis.UI.Services.Tray;
|
||||||
using Artemis.UI.Services.Updating;
|
using Artemis.UI.Services.Updating;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
@@ -16,6 +17,7 @@ using Artemis.WebClient.Workshop.Services;
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Platform;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@@ -34,6 +36,11 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
|
|||||||
private readonly IUpdateService _updateService;
|
private readonly IUpdateService _updateService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly ObservableAsPropertyHelper<ViewModelBase?> _titleBarViewModel;
|
private readonly ObservableAsPropertyHelper<ViewModelBase?> _titleBarViewModel;
|
||||||
|
private readonly PluginSetting<bool> _monochromeTrayIcon;
|
||||||
|
private readonly ITrayThemeProvider _trayThemeProvider;
|
||||||
|
private WindowIcon? _coloredTrayIcon;
|
||||||
|
private WindowIcon? _blackTrayIcon;
|
||||||
|
private WindowIcon? _whiteTrayIcon;
|
||||||
|
|
||||||
public RootViewModel(ILogger logger,
|
public RootViewModel(ILogger logger,
|
||||||
IRouter router,
|
IRouter router,
|
||||||
@@ -45,6 +52,7 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
|
|||||||
IDebugService debugService,
|
IDebugService debugService,
|
||||||
IUpdateService updateService,
|
IUpdateService updateService,
|
||||||
IWorkshopService workshopService,
|
IWorkshopService workshopService,
|
||||||
|
ITrayThemeProvider trayThemeProvider,
|
||||||
SidebarViewModel sidebarViewModel,
|
SidebarViewModel sidebarViewModel,
|
||||||
DefaultTitleBarViewModel defaultTitleBarViewModel)
|
DefaultTitleBarViewModel defaultTitleBarViewModel)
|
||||||
{
|
{
|
||||||
@@ -60,8 +68,17 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
|
|||||||
_debugService = debugService;
|
_debugService = debugService;
|
||||||
_updateService = updateService;
|
_updateService = updateService;
|
||||||
_defaultTitleBarViewModel = defaultTitleBarViewModel;
|
_defaultTitleBarViewModel = defaultTitleBarViewModel;
|
||||||
|
_trayThemeProvider = trayThemeProvider;
|
||||||
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!;
|
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!;
|
||||||
|
|
||||||
|
_monochromeTrayIcon = settingsService.GetSetting("UI.MonochromeTrayIcon", false);
|
||||||
|
_monochromeTrayIcon.SettingChanged += (_, _) =>
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(MonochromeTrayIcon));
|
||||||
|
this.RaisePropertyChanged(nameof(TrayIcon));
|
||||||
|
};
|
||||||
|
_trayThemeProvider.TrayThemeChanged += (_, _) => Dispatcher.UIThread.Post(() => this.RaisePropertyChanged(nameof(TrayIcon)));
|
||||||
|
|
||||||
router.SetRoot(this);
|
router.SetRoot(this);
|
||||||
mainWindowService.ConfigureMainWindowProvider(this);
|
mainWindowService.ConfigureMainWindowProvider(this);
|
||||||
|
|
||||||
@@ -117,6 +134,26 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
|
|||||||
public ReactiveCommand<Unit, Unit> Exit { get; }
|
public ReactiveCommand<Unit, Unit> Exit { get; }
|
||||||
|
|
||||||
public ViewModelBase? TitleBarViewModel => _titleBarViewModel.Value;
|
public ViewModelBase? TitleBarViewModel => _titleBarViewModel.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the tray icon is black or white rather than colored.
|
||||||
|
/// </summary>
|
||||||
|
public bool MonochromeTrayIcon => _monochromeTrayIcon.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the tray icon, in black or white to match the system tray when <see cref="MonochromeTrayIcon" /> is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public WindowIcon TrayIcon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_monochromeTrayIcon.Value)
|
||||||
|
return _coloredTrayIcon ??= LoadTrayIcon("application");
|
||||||
|
return _trayThemeProvider.IsTrayDark
|
||||||
|
? _whiteTrayIcon ??= LoadTrayIcon("application-monochrome-white")
|
||||||
|
: _blackTrayIcon ??= LoadTrayIcon("application-monochrome-black");
|
||||||
|
}
|
||||||
|
}
|
||||||
public static PluginSetting<WindowSize?>? WindowSizeSetting { get; private set; }
|
public static PluginSetting<WindowSize?>? WindowSizeSetting { get; private set; }
|
||||||
|
|
||||||
public void GoBack()
|
public void GoBack()
|
||||||
@@ -188,6 +225,11 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
|
|||||||
|
|
||||||
#region Implementation of IMainWindowProvider
|
#region Implementation of IMainWindowProvider
|
||||||
|
|
||||||
|
private static WindowIcon LoadTrayIcon(string name)
|
||||||
|
{
|
||||||
|
return new WindowIcon(AssetLoader.Open(new Uri($"avares://Artemis.UI/Assets/Images/Logo/{name}.ico")));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsMainWindowOpen => _lifeTime.MainWindow != null;
|
public bool IsMainWindowOpen => _lifeTime.MainWindow != null;
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,19 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Border Classes="card-separator" IsVisible="{CompiledBinding IsWindows11}"/>
|
<Border Classes="card-separator" IsVisible="{CompiledBinding IsWindows11}"/>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<TextBlock>Monochrome tray icon</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle" TextWrapping="Wrap">
|
||||||
|
Show a black or white icon in the system tray instead of the colored one, matching your light or dark mode.
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||||
|
<ToggleSwitch IsChecked="{CompiledBinding UIMonochromeTrayIcon.Value}" OnContent="Yes" OffContent="No" MinWidth="0" Margin="0 -10" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
<StackPanel Grid.Column="0">
|
<StackPanel Grid.Column="0">
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ public class GeneralTabViewModel : RoutableScreen
|
|||||||
public PluginSetting<int> UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15);
|
public PluginSetting<int> UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15);
|
||||||
public PluginSetting<bool> UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", true);
|
public PluginSetting<bool> UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", true);
|
||||||
public PluginSetting<bool> EnableMica => _settingsService.GetSetting("UI.EnableMica", true);
|
public PluginSetting<bool> EnableMica => _settingsService.GetSetting("UI.EnableMica", true);
|
||||||
|
public PluginSetting<bool> UIMonochromeTrayIcon => _settingsService.GetSetting("UI.MonochromeTrayIcon", false);
|
||||||
public PluginSetting<bool> UICheckForUpdates => _settingsService.GetSetting("UI.Updating.AutoCheck", true);
|
public PluginSetting<bool> UICheckForUpdates => _settingsService.GetSetting("UI.Updating.AutoCheck", true);
|
||||||
public PluginSetting<bool> WorkshopShowNotifications => _settingsService.GetSetting("Workshop.ShowNotifications", true);
|
public PluginSetting<bool> WorkshopShowNotifications => _settingsService.GetSetting("Workshop.ShowNotifications", true);
|
||||||
public PluginSetting<bool> UIAutoUpdate => _settingsService.GetSetting("UI.Updating.AutoInstall", true);
|
public PluginSetting<bool> UIAutoUpdate => _settingsService.GetSetting("UI.Updating.AutoInstall", true);
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Platform;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Services.Tray;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the light or dark mode of the system tray based on the light or dark mode of the operating system.
|
||||||
|
/// </summary>
|
||||||
|
public class BasicTrayThemeProvider : ITrayThemeProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BasicTrayThemeProvider" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public BasicTrayThemeProvider()
|
||||||
|
{
|
||||||
|
if (Application.Current?.PlatformSettings is { } platformSettings)
|
||||||
|
platformSettings.ColorValuesChanged += (_, _) => TrayThemeChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsTrayDark => Application.Current?.PlatformSettings?.GetColorValues().ThemeVariant != PlatformThemeVariant.Light;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler? TrayThemeChanged;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Services.Tray;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the light or dark mode of the system tray.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITrayThemeProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the system tray has a dark background.
|
||||||
|
/// </summary>
|
||||||
|
bool IsTrayDark { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the background of the system tray may have changed, possibly on a background thread.
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler? TrayThemeChanged;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user