Add the "Auto" theme option in setting (#6611)
* Add "Follow OS theme" option * Update App.axaml.cs * Add "Follow OS theme" option * Update App.axaml.cs * Remove `this` * Remove annotation for nullable reference * Change into switch expression to make it concise * Change comments to XML docs * Update en_US.json * Fix icons in About dialog do not response to "auto" theme The theme icons seemingly use Dark variant event when the OS theme is light. In addition, I added ThemeManager common to make it accessible for both App and AboutWindow * Newline at the end * newline moment * Update ThemeManager.cs * bait to switch to lf * change to lf * temp. revert * Add back ThemeManager.cs common, pls pass the format check * I found the mistake: should have put `ThemeManager.OnThemeChanged();` in try block Finally solve the formatting check * test formatting * Update App.axaml.cs * Ok i seem to forget to add version lol * Fix info CA1816
This commit is contained in:
parent
075575200d
commit
2b6cc4b353
7 changed files with 128 additions and 21 deletions
|
@ -1,8 +1,10 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.Platform;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
@ -84,7 +86,7 @@ namespace Ryujinx.Ava
|
||||||
ApplyConfiguredTheme();
|
ApplyConfiguredTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyConfiguredTheme()
|
public void ApplyConfiguredTheme()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -92,13 +94,18 @@ namespace Ryujinx.Ava
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(baseStyle))
|
if (string.IsNullOrWhiteSpace(baseStyle))
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.UI.BaseStyle.Value = "Dark";
|
ConfigurationState.Instance.UI.BaseStyle.Value = "Auto";
|
||||||
|
|
||||||
baseStyle = ConfigurationState.Instance.UI.BaseStyle;
|
baseStyle = ConfigurationState.Instance.UI.BaseStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThemeVariant systemTheme = DetectSystemTheme();
|
||||||
|
|
||||||
|
ThemeManager.OnThemeChanged();
|
||||||
|
|
||||||
RequestedThemeVariant = baseStyle switch
|
RequestedThemeVariant = baseStyle switch
|
||||||
{
|
{
|
||||||
|
"Auto" => systemTheme,
|
||||||
"Light" => ThemeVariant.Light,
|
"Light" => ThemeVariant.Light,
|
||||||
"Dark" => ThemeVariant.Dark,
|
"Dark" => ThemeVariant.Dark,
|
||||||
_ => ThemeVariant.Default,
|
_ => ThemeVariant.Default,
|
||||||
|
@ -111,5 +118,28 @@ namespace Ryujinx.Ava
|
||||||
ShowRestartDialog();
|
ShowRestartDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a PlatformThemeVariant value to the corresponding ThemeVariant value.
|
||||||
|
/// </summary>
|
||||||
|
public static ThemeVariant ConvertThemeVariant(PlatformThemeVariant platformThemeVariant) =>
|
||||||
|
platformThemeVariant switch
|
||||||
|
{
|
||||||
|
PlatformThemeVariant.Dark => ThemeVariant.Dark,
|
||||||
|
PlatformThemeVariant.Light => ThemeVariant.Light,
|
||||||
|
_ => ThemeVariant.Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ThemeVariant DetectSystemTheme()
|
||||||
|
{
|
||||||
|
if (Application.Current is App app)
|
||||||
|
{
|
||||||
|
var colorValues = app.PlatformSettings.GetColorValues();
|
||||||
|
|
||||||
|
return ConvertThemeVariant(colorValues.ThemeVariant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThemeVariant.Default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,6 +404,7 @@
|
||||||
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
||||||
"SettingsTabGeneralTheme": "Theme:",
|
"SettingsTabGeneralTheme": "Theme:",
|
||||||
|
"SettingsTabGeneralThemeAuto": "Auto",
|
||||||
"SettingsTabGeneralThemeDark": "Dark",
|
"SettingsTabGeneralThemeDark": "Dark",
|
||||||
"SettingsTabGeneralThemeLight": "Light",
|
"SettingsTabGeneralThemeLight": "Light",
|
||||||
"ControllerSettingsConfigureGeneral": "Configure",
|
"ControllerSettingsConfigureGeneral": "Configure",
|
||||||
|
|
14
src/Ryujinx/Common/ThemeManager.cs
Normal file
14
src/Ryujinx/Common/ThemeManager.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Common
|
||||||
|
{
|
||||||
|
public static class ThemeManager
|
||||||
|
{
|
||||||
|
public static event EventHandler ThemeChanged;
|
||||||
|
|
||||||
|
public static void OnThemeChanged()
|
||||||
|
{
|
||||||
|
ThemeChanged?.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
using Avalonia.Styling;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
|
@ -11,7 +13,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
public class AboutWindowViewModel : BaseModel
|
public class AboutWindowViewModel : BaseModel, IDisposable
|
||||||
{
|
{
|
||||||
private Bitmap _githubLogo;
|
private Bitmap _githubLogo;
|
||||||
private Bitmap _discordLogo;
|
private Bitmap _discordLogo;
|
||||||
|
@ -86,23 +88,39 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
public AboutWindowViewModel()
|
public AboutWindowViewModel()
|
||||||
{
|
{
|
||||||
Version = Program.Version;
|
Version = Program.Version;
|
||||||
|
UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value);
|
||||||
if (ConfigurationState.Instance.UI.BaseStyle.Value == "Light")
|
|
||||||
{
|
|
||||||
GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.UI.Common")));
|
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson);
|
Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson);
|
||||||
|
|
||||||
|
ThemeManager.ThemeChanged += ThemeManager_ThemeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThemeManager_ThemeChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLogoTheme(string theme)
|
||||||
|
{
|
||||||
|
bool isDarkTheme = theme == "Dark" || (theme == "Auto" && App.DetectSystemTheme() == ThemeVariant.Dark);
|
||||||
|
|
||||||
|
string basePath = "resm:Ryujinx.UI.Common.Resources.";
|
||||||
|
string themeSuffix = isDarkTheme ? "Dark.png" : "Light.png";
|
||||||
|
|
||||||
|
GithubLogo = LoadBitmap($"{basePath}Logo_GitHub_{themeSuffix}?assembly=Ryujinx.UI.Common");
|
||||||
|
DiscordLogo = LoadBitmap($"{basePath}Logo_Discord_{themeSuffix}?assembly=Ryujinx.UI.Common");
|
||||||
|
PatreonLogo = LoadBitmap($"{basePath}Logo_Patreon_{themeSuffix}?assembly=Ryujinx.UI.Common");
|
||||||
|
TwitterLogo = LoadBitmap($"{basePath}Logo_Twitter_{themeSuffix}?assembly=Ryujinx.UI.Common");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap LoadBitmap(string uri)
|
||||||
|
{
|
||||||
|
return new Bitmap(Avalonia.Platform.AssetLoader.Open(new Uri(uri)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPatronsJson()
|
private async Task DownloadPatronsJson()
|
||||||
|
|
|
@ -397,7 +397,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
GameDirectories.Clear();
|
GameDirectories.Clear();
|
||||||
GameDirectories.AddRange(config.UI.GameDirs.Value);
|
GameDirectories.AddRange(config.UI.GameDirs.Value);
|
||||||
|
|
||||||
BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1;
|
BaseStyleIndex = config.UI.BaseStyle.Value switch
|
||||||
|
{
|
||||||
|
"Auto" => 0,
|
||||||
|
"Light" => 1,
|
||||||
|
"Dark" => 2,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
EnableDockedMode = config.System.EnableDockedMode;
|
EnableDockedMode = config.System.EnableDockedMode;
|
||||||
|
@ -486,7 +492,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
config.UI.GameDirs.Value = gameDirs;
|
config.UI.GameDirs.Value = gameDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
|
config.UI.BaseStyle.Value = BaseStyleIndex switch
|
||||||
|
{
|
||||||
|
0 => "Auto",
|
||||||
|
1 => "Light",
|
||||||
|
2 => "Dark",
|
||||||
|
_ => "Auto"
|
||||||
|
};
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
config.System.EnableDockedMode.Value = EnableDockedMode;
|
config.System.EnableDockedMode.Value = EnableDockedMode;
|
||||||
|
|
|
@ -65,6 +65,9 @@
|
||||||
<ComboBox SelectedIndex="{Binding BaseStyleIndex}"
|
<ComboBox SelectedIndex="{Binding BaseStyleIndex}"
|
||||||
HorizontalContentAlignment="Left"
|
HorizontalContentAlignment="Left"
|
||||||
MinWidth="100">
|
MinWidth="100">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeAuto}" />
|
||||||
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem>
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeLight}" />
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeLight}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
|
|
|
@ -2,6 +2,7 @@ using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Platform;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common;
|
using Ryujinx.Ava.Common;
|
||||||
|
@ -92,6 +93,29 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event handler for detecting OS theme change when using "Follow OS theme" option
|
||||||
|
/// </summary>
|
||||||
|
private void OnPlatformColorValuesChanged(object sender, PlatformColorValues e)
|
||||||
|
{
|
||||||
|
if (Application.Current is App app)
|
||||||
|
{
|
||||||
|
app.ApplyConfiguredTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosed(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnClosed(e);
|
||||||
|
if (PlatformSettings != null)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Unsubscribe to the ColorValuesChanged event
|
||||||
|
/// </summary>
|
||||||
|
PlatformSettings.ColorValuesChanged -= OnPlatformColorValuesChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
|
@ -390,6 +414,11 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subscribe to the ColorValuesChanged event
|
||||||
|
/// </summary>
|
||||||
|
PlatformSettings.ColorValuesChanged += OnPlatformColorValuesChanged;
|
||||||
|
|
||||||
ViewModel.Initialize(
|
ViewModel.Initialize(
|
||||||
ContentManager,
|
ContentManager,
|
||||||
StorageProvider,
|
StorageProvider,
|
||||||
|
|
Reference in a new issue