diff --git a/src/Ryujinx/Common/EmbeddedAvaloniaResources.cs b/src/Ryujinx/Common/EmbeddedAvaloniaResources.cs new file mode 100644 index 000000000..57be9da4a --- /dev/null +++ b/src/Ryujinx/Common/EmbeddedAvaloniaResources.cs @@ -0,0 +1,31 @@ +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Styling; +using Gommon; +using System; + +namespace Ryujinx.Ava.Common +{ + public static class EmbeddedAvaloniaResources + { + public const string LogoPathFormat = "resm:Ryujinx.Assets.UIImages.Logo_{0}_{1}.png?assembly=Ryujinx"; + + public static Bitmap LoadBitmap(string uri) + => new(AssetLoader.Open(new Uri(uri))); + + public static Bitmap GetIconByNameAndTheme(string iconName, bool isDarkTheme) + { + string themeName = isDarkTheme ? "Dark" : "Light"; + + return LoadBitmap(LogoPathFormat.Format(iconName, themeName)); + } + + public static Bitmap GetIconByNameAndTheme(string iconName, string theme) + { + bool isDarkTheme = theme == "Dark" || + (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark); + + return GetIconByNameAndTheme(iconName, isDarkTheme); + } + } +} diff --git a/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs index 34c4c492e..7c7d93340 100644 --- a/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs +++ b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs @@ -71,7 +71,7 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages } } - public override Control CreateHelpContent() + public override object CreateHelpContent() { Grid grid = new() { diff --git a/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs index 60f2957e4..35af2efa7 100644 --- a/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs +++ b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs @@ -26,7 +26,7 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages ? Result.Fail : InstallKeys(KeysFolderPath); - public override Control CreateHelpContent() + public override object CreateHelpContent() { Grid grid = new() { diff --git a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.Steps.cs b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.Steps.cs new file mode 100644 index 000000000..9f5637baa --- /dev/null +++ b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.Steps.cs @@ -0,0 +1,57 @@ +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.SetupWizard.Pages; +using System.Threading.Tasks; + +namespace Ryujinx.Ava.UI.SetupWizard +{ + public partial class RyujinxSetupWizard + { + private async ValueTask SetupKeys() + { + if (_overwrite || !RyujinxApp.MainWindow.VirtualFileSystem.HasKeySet) + { + Retry: + bool result = await NextPage() + .WithTitle(LocaleKeys.SetupWizardKeysPageTitle) + .WithContent(out SetupKeysPageContext keyContext) + .Show(); + + if (!result) + return false; + + if (!keyContext.CompleteStep()) + goto Retry; + } + + return true; + } + + private async ValueTask SetupFirmware() + { + if (_overwrite || !HasFirmware) + { + if (!RyujinxApp.MainWindow.VirtualFileSystem.HasKeySet) + { + NotificationManager.Error("Keys still seem to not be installed. Please try again."); + return false; + } + + Retry: + bool result = await NextPage() + .WithTitle(LocaleKeys.SetupWizardFirmwarePageTitle) + .WithContent(out SetupFirmwarePageContext fwContext) + .Show(); + + if (!result) + return false; + + if (!fwContext.CompleteStep()) + goto Retry; + + OnPropertyChanged(nameof(HasFirmware)); + } + + return true; + } + } +} diff --git a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs index 79433295e..8843b0f18 100644 --- a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs +++ b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs @@ -3,24 +3,46 @@ using Avalonia.Controls.Notifications; using Avalonia.Media.Imaging; using Avalonia.Styling; using Avalonia.Threading; -using Gommon; +using CommunityToolkit.Mvvm.ComponentModel; +using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.SetupWizard.Pages; +using Ryujinx.Ava.UI.ViewModels; using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.SetupWizard { - public class RyujinxSetupWizard : IDisposable, INotifyPropertyChanged + public partial class RyujinxSetupWizard : BaseModel, IDisposable { private bool _configWasModified; - public bool HasFirmware => RyujinxApp.MainWindow.ContentManager.GetCurrentFirmwareVersion() != null; + private readonly RyujinxSetupWizardWindow _window; + private readonly bool _overwrite; + + public RyujinxSetupWizard(RyujinxSetupWizardWindow wizardWindow, bool overwriteMode) + { + _window = wizardWindow; + _overwrite = overwriteMode; + + if (Program.PreviewerDetached) + { + UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle); + RyujinxApp.ThemeChanged += Ryujinx_ThemeChanged; + } + } + + private SetupWizardPage FirstPage() => new(_window.WizardPresenter, this, isFirstPage: true); + + private SetupWizardPage NextPage() => new(_window.WizardPresenter, this); + + public void SignalConfigModified() + { + _configWasModified = true; + } + + public static bool HasFirmware => RyujinxApp.MainWindow.ContentManager.GetCurrentFirmwareVersion() != null; public RyujinxNotificationManager NotificationManager { get; private set; } @@ -40,7 +62,7 @@ namespace Ryujinx.Ava.UI.SetupWizard .WithTitle(LocaleKeys.SetupWizardFirstPageTitle) .WithContent(LocaleKeys.SetupWizardFirstPageContent) .WithActionContent(LocaleKeys.SetupWizardFirstPageAction) - .Show(); + .Show(); // result is unhandled as the first page cannot display anything other than the next button. // back does not need to be handled @@ -61,99 +83,22 @@ namespace Ryujinx.Ava.UI.SetupWizard RyujinxSetupWizardWindow.IsOpen = false; } - public Bitmap DiscordLogo - { - get; - set => SetField(ref field, value); - } + #region Discord logo stuff + + [ObservableProperty] public partial Bitmap DiscordLogo { get; set; } private void Ryujinx_ThemeChanged() { - Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value)); + Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle)); } - private const string LogoPathFormat = "resm:Ryujinx.Assets.UIImages.Logo_{0}_{1}.png?assembly=Ryujinx"; - private void UpdateLogoTheme(string theme) { bool isDarkTheme = theme == "Dark" || (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark); - string themeName = isDarkTheme ? "Dark" : "Light"; - - DiscordLogo = LoadBitmap(LogoPathFormat.Format("Discord", themeName)); - } - - private static Bitmap LoadBitmap(string uri) => new(Avalonia.Platform.AssetLoader.Open(new Uri(uri))); - - private async ValueTask SetupKeys() - { - if (_overwrite || !RyujinxApp.MainWindow.VirtualFileSystem.HasKeySet) - { - Retry: - bool result = await NextPage() - .WithTitle(LocaleKeys.SetupWizardKeysPageTitle) - .WithContent(out SetupKeysPageContext keyContext) - .Show(); - - if (!result) - return false; - - if (!keyContext.CompleteStep()) - goto Retry; - } - - return true; - } - - private async ValueTask SetupFirmware() - { - if (_overwrite || !HasFirmware) - { - if (!RyujinxApp.MainWindow.VirtualFileSystem.HasKeySet) - { - NotificationManager.Error("Keys still seem to not be installed. Please try again."); - return false; - } - - Retry: - bool result = await NextPage() - .WithTitle(LocaleKeys.SetupWizardFirmwarePageTitle) - .WithContent(out SetupFirmwarePageContext fwContext) - .Show(); - - if (!result) - return false; - - if (!fwContext.CompleteStep()) - goto Retry; - } - - return true; - } - - private SetupWizardPage FirstPage() => new(_window.WizardPresenter, this, isFirstPage: true); - - private SetupWizardPage NextPage() => new(_window.WizardPresenter, this); - - public void SignalConfigModified() - { - _configWasModified = true; - } - - private readonly RyujinxSetupWizardWindow _window; - private readonly bool _overwrite; - - public RyujinxSetupWizard(RyujinxSetupWizardWindow wizardWindow, bool overwriteMode) - { - _window = wizardWindow; - _overwrite = overwriteMode; - - if (Program.PreviewerDetached) - { - UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle); - RyujinxApp.ThemeChanged += Ryujinx_ThemeChanged; - } + DiscordLogo = EmbeddedAvaloniaResources + .GetIconByNameAndTheme("Discord", isDarkTheme); } public void Dispose() @@ -165,19 +110,6 @@ namespace Ryujinx.Ava.UI.SetupWizard GC.SuppressFinalize(this); } - public event PropertyChangedEventHandler PropertyChanged; - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) - { - if (EqualityComparer.Default.Equals(field, value)) return false; - field = value; - OnPropertyChanged(propertyName); - return true; - } + #endregion } } diff --git a/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs index 6b3a09fa1..30d84e554 100644 --- a/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs @@ -1,5 +1,7 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; using Gommon; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Controls; @@ -35,6 +37,23 @@ namespace Ryujinx.Ava.UI.SetupWizard public SetupWizardPage WithHelpContent(object? content) { + if (content is string str) + { + TextBlock tb = new() + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + TextAlignment = TextAlignment.Center, + TextWrapping = TextWrapping.Wrap, + FontSize = 20.0, + Text = str + }; + + tb.Classes.Add("h1"); + + content = tb; + } + HelpContent = content; HasHelpContent = content != null; return this; diff --git a/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs index 147f995bf..605270761 100644 --- a/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs @@ -1,4 +1,3 @@ -using Avalonia.Controls; using Gommon; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; @@ -10,8 +9,9 @@ namespace Ryujinx.Ava.UI.SetupWizard public RyujinxNotificationManager NotificationManager { get; init; } public abstract Result CompleteStep(); - - public virtual Control CreateHelpContent() +#nullable enable + public virtual object? CreateHelpContent() +#nullable disable { return null; } diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index 47a99d886..d30c619aa 100644 --- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -3,6 +3,7 @@ using Avalonia.Styling; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using Gommon; +using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Systems.Configuration; using System; @@ -36,21 +37,15 @@ namespace Ryujinx.Ava.UI.ViewModels Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value)); } - private const string LogoPathFormat = "resm:Ryujinx.Assets.UIImages.Logo_{0}_{1}.png?assembly=Ryujinx"; - private void UpdateLogoTheme(string theme) { bool isDarkTheme = theme == "Dark" || (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark); - string themeName = isDarkTheme ? "Dark" : "Light"; - - DiscordLogo = LoadBitmap(LogoPathFormat.Format("Discord", themeName)); - GitLabLogo = LoadBitmap(LogoPathFormat.Format("GitLab", themeName)); + DiscordLogo = EmbeddedAvaloniaResources.GetIconByNameAndTheme("Discord", isDarkTheme); + GitLabLogo = EmbeddedAvaloniaResources.GetIconByNameAndTheme("GitLab", isDarkTheme); } - private static Bitmap LoadBitmap(string uri) => new(Avalonia.Platform.AssetLoader.Open(new Uri(uri))); - public void Dispose() { RyujinxApp.ThemeChanged -= Ryujinx_ThemeChanged;