Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Artemis.UI.Linux/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<TrayIcon.Icons>
<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>
<NativeMenu>
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
Expand Down
2 changes: 1 addition & 1 deletion src/Artemis.UI.MacOS/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<TrayIcon.Icons>
<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>
<NativeMenu>
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
Expand Down
2 changes: 1 addition & 1 deletion src/Artemis.UI.Windows/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<TrayIcon.Icons>
<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>
<NativeMenu>
<NativeMenuItem Header="Home" Command="{CompiledBinding OpenScreen}" CommandParameter="home" />
Expand Down
2 changes: 2 additions & 0 deletions src/Artemis.UI.Windows/DryIoc/ContainerExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Artemis.Core.Providers;
using Artemis.Core.Services;
using Artemis.UI.Services.Tray;
using Artemis.UI.Services.Updating;
using Artemis.UI.Shared.Providers;
using Artemis.UI.Windows.Providers;
Expand All @@ -25,5 +26,6 @@ public static void RegisterProviders(this IContainer container)
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>();
container.Register<IProtocolProvider, ProtocolProvider>();
container.Register<ITrayThemeProvider, WindowsTrayThemeProvider>(Reuse.Singleton);
}
}
49 changes: 49 additions & 0 deletions src/Artemis.UI.Windows/Providers/WindowsTrayThemeProvider.cs
Original file line number Diff line number Diff line change
@@ -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.
Binary file not shown.
2 changes: 2 additions & 0 deletions src/Artemis.UI/DryIoc/ContainerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Artemis.UI.Screens.Device.Layout.LayoutProviders;
using Artemis.UI.Screens.VisualScripting;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Services.Tray;
using Artemis.UI.Services.Updating;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.NodeEditor;
Expand Down Expand Up @@ -33,6 +34,7 @@ public static void RegisterUI(this IContainer container)
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
container.Register<IPropertyVmFactory, PropertyVmFactory>(Reuse.Singleton);
container.Register<IUpdateNotificationProvider, BasicUpdateNotificationProvider>();
container.Register<ITrayThemeProvider, BasicTrayThemeProvider>(Reuse.Singleton);

container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IArtemisUIService>(), Reuse.Singleton);
}
Expand Down
42 changes: 42 additions & 0 deletions src/Artemis.UI/Screens/Root/RootViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Artemis.UI.Models;
using Artemis.UI.Screens.Sidebar;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Services.Tray;
using Artemis.UI.Services.Updating;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
Expand All @@ -16,6 +17,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
using Avalonia.Threading;
using ReactiveUI;
using Serilog;
Expand All @@ -34,6 +36,11 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
private readonly IUpdateService _updateService;
private readonly IWindowService _windowService;
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,
IRouter router,
Expand All @@ -45,6 +52,7 @@ public RootViewModel(ILogger logger,
IDebugService debugService,
IUpdateService updateService,
IWorkshopService workshopService,
ITrayThemeProvider trayThemeProvider,
SidebarViewModel sidebarViewModel,
DefaultTitleBarViewModel defaultTitleBarViewModel)
{
Expand All @@ -60,8 +68,17 @@ public RootViewModel(ILogger logger,
_debugService = debugService;
_updateService = updateService;
_defaultTitleBarViewModel = defaultTitleBarViewModel;
_trayThemeProvider = trayThemeProvider;
_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);
mainWindowService.ConfigureMainWindowProvider(this);

Expand Down Expand Up @@ -117,6 +134,26 @@ public RootViewModel(ILogger logger,
public ReactiveCommand<Unit, Unit> Exit { get; }

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 void GoBack()
Expand Down Expand Up @@ -188,6 +225,11 @@ private async Task ExecuteExit()

#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 />
public bool IsMainWindowOpen => _lifeTime.MainWindow != null;

Expand Down
13 changes: 13 additions & 0 deletions src/Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@
</StackPanel>
</Grid>
<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">
<StackPanel Grid.Column="0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public RenderSettingViewModel? SelectedTargetFrameRate
public PluginSetting<int> UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15);
public PluginSetting<bool> UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", 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> WorkshopShowNotifications => _settingsService.GetSetting("Workshop.ShowNotifications", true);
public PluginSetting<bool> UIAutoUpdate => _settingsService.GetSetting("UI.Updating.AutoInstall", true);
Expand Down
26 changes: 26 additions & 0 deletions src/Artemis.UI/Services/Tray/BasicTrayThemeProvider.cs
Original file line number Diff line number Diff line change
@@ -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;
}
19 changes: 19 additions & 0 deletions src/Artemis.UI/Services/Tray/ITrayThemeProvider.cs
Original file line number Diff line number Diff line change
@@ -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;
}
Loading