diff --git a/src/Ryujinx/Systems/SetupWizard/BaseSetupWizard.cs b/src/Ryujinx/Systems/SetupWizard/BaseSetupWizard.cs deleted file mode 100644 index 93fb02a64..000000000 --- a/src/Ryujinx/Systems/SetupWizard/BaseSetupWizard.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Avalonia.Controls.Presenters; -using Ryujinx.Ava.Common.Locale; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.Systems.SetupWizard -{ - public abstract class BaseSetupWizard(ContentPresenter presenter) - { - /// - /// Define the logic and flow of this . - /// - public abstract Task Start(); - - protected SetupWizardPage FirstPage() - => new(presenter, isFirstPage: true); - - protected SetupWizardPage NextPage() - => new(presenter); - } -} diff --git a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageContext.cs b/src/Ryujinx/Systems/SetupWizard/SetupWizardPageContext.cs deleted file mode 100644 index 9107a8f0b..000000000 --- a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageContext.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Gommon; -using Ryujinx.Ava.UI.ViewModels; - -namespace Ryujinx.Ava.Systems.SetupWizard -{ - public abstract class SetupWizardPageContext: BaseModel - { - public abstract Result CompleteStep(); - } -} diff --git a/src/Ryujinx/UI/Helpers/NotificationHelper.cs b/src/Ryujinx/UI/Helpers/NotificationHelper.cs index f26b92398..db9a1c71e 100644 --- a/src/Ryujinx/UI/Helpers/NotificationHelper.cs +++ b/src/Ryujinx/UI/Helpers/NotificationHelper.cs @@ -11,22 +11,24 @@ using System.Threading; namespace Ryujinx.Ava.UI.Helpers { - public static class NotificationHelper + public class NotificationHelper { + public static NotificationHelper Shared { get; set; } + private const int MaxNotifications = 4; private const int NotificationDelayInMs = 5000; - private static WindowNotificationManager _notificationManager; + private readonly WindowNotificationManager _notificationManager; - private static readonly BlockingCollection _notifications = new(); + private readonly BlockingCollection _notifications = new(); - public static void SetNotificationManager(Window host) + public NotificationHelper(Window host) { _notificationManager = new WindowNotificationManager(host) { Position = NotificationPosition.BottomRight, MaxItems = MaxNotifications, - Margin = new Thickness(0, 0, 15, 40), + Margin = new Thickness(0, 0, 15, 40) }; Lazy> maybeAsyncWorkQueue = new( @@ -49,8 +51,6 @@ namespace Ryujinx.Ava.UI.Helpers host.Closing += (sender, args) => { - if (sender is RyujinxSetupWizardWindow) return; - if (maybeAsyncWorkQueue.IsValueCreated) { maybeAsyncWorkQueue.Value.Dispose(); @@ -58,21 +58,75 @@ namespace Ryujinx.Ava.UI.Helpers }; } - public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null) + public static void Show(string title, string text, NotificationType type, bool waitingExit = false, + Action onClick = null, Action onClose = null) + => Shared?.Notify(title, text, type, waitingExit, onClick, onClose); + + public void Notify(string title, string text, NotificationType type, bool waitingExit = false, + Action onClick = null, Action onClose = null) { - TimeSpan delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs); + TimeSpan delay = waitingExit + ? TimeSpan.FromMilliseconds(0) + : TimeSpan.FromMilliseconds(NotificationDelayInMs); _notifications.Add(new Notification(title, text, type, delay, onClick, onClose)); } - public static void ShowError(string message, bool waitingExit = false) => - ShowError( + #region Instance notification senders + + public void NotifyInformation(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => + Notify( + title, + text, + NotificationType.Information, + waitingExit, + onClick, + onClose); + + public void NotifySuccess(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => + Notify( + title, + text, + NotificationType.Success, + waitingExit, + onClick, + onClose); + + public void NotifyWarning(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => + Notify( + title, + text, + NotificationType.Warning, + waitingExit, + onClick, + onClose); + + public void NotifyError(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => + Notify( + title, + text, + NotificationType.Error, + waitingExit, + onClick, + onClose); + + public void NotifyError(string message, bool waitingExit = false) => + NotifyError( LocaleManager.Instance[LocaleKeys.DialogErrorTitle], $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}", waitingExit: waitingExit ); - public static void ShowInformation(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + #endregion + + #region Static notification senders + + public static void ShowInformation(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => Show( title, text, @@ -81,7 +135,8 @@ namespace Ryujinx.Ava.UI.Helpers onClick, onClose); - public static void ShowSuccess(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + public static void ShowSuccess(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => Show( title, text, @@ -90,7 +145,8 @@ namespace Ryujinx.Ava.UI.Helpers onClick, onClose); - public static void ShowWarning(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + public static void ShowWarning(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => Show( title, text, @@ -99,7 +155,8 @@ namespace Ryujinx.Ava.UI.Helpers onClick, onClose); - public static void ShowError(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + public static void ShowError(string title, string text, bool waitingExit = false, Action onClick = null, + Action onClose = null) => Show( title, text, @@ -107,5 +164,14 @@ namespace Ryujinx.Ava.UI.Helpers waitingExit, onClick, onClose); + + public static void ShowError(string message, bool waitingExit = false) => + ShowError( + LocaleManager.Instance[LocaleKeys.DialogErrorTitle], + $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}", + waitingExit: waitingExit + ); + + #endregion } } diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePage.axaml b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePage.axaml similarity index 100% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePage.axaml rename to src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePage.axaml diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePage.axaml.cs b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePage.axaml.cs similarity index 100% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePage.axaml.cs rename to src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePage.axaml.cs diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePageContext.cs b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs similarity index 92% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePageContext.cs rename to src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs index 0359fab88..bdc2fed20 100644 --- a/src/Ryujinx/UI/SetupWizard/Pages/SetupFirmwarePageContext.cs +++ b/src/Ryujinx/UI/SetupWizard/Pages/Fw/SetupFirmwarePageContext.cs @@ -4,8 +4,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Gommon; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Systems.SetupWizard; -using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.Utilities; using Ryujinx.Common.Configuration; using Ryujinx.HLE.FileSystem; @@ -81,14 +79,14 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages SystemVersion installedFwVer = RyujinxApp.MainWindow.ContentManager.GetCurrentFirmwareVersion(); if (installedFwVer != null) { - NotificationHelper.ShowInformation( + Notifications.NotifyInformation( "Firmware installed", $"Installed firmware version {installedFwVer.VersionString}." ); } else { - NotificationHelper.ShowError( + Notifications.NotifyError( "Firmware not installed", $"It seems some error occurred when trying to install the firmware at path '{FirmwareSourcePath}'." + "\nDid that folder contain a firmware dump?" @@ -96,9 +94,6 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages } RyujinxApp.MainWindow.ViewModel.RefreshFirmwareStatus(installedFwVer, allowNullVersion: true); - if (installedFwVer is null) - return Result.Fail; - // Purge Applet Cache. DirectoryInfo miiEditorCacheFolder = new( @@ -112,7 +107,7 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages } catch (Exception e) { - NotificationHelper.ShowError(e.Message, waitingExit: true); + Notifications.NotifyError(e.Message, waitingExit: true); return Result.Fail; } diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPage.axaml b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPage.axaml similarity index 100% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPage.axaml rename to src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPage.axaml diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPage.axaml.cs b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPage.axaml.cs similarity index 100% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPage.axaml.cs rename to src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPage.axaml.cs diff --git a/src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPageContext.cs b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs similarity index 88% rename from src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPageContext.cs rename to src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs index 8b0543957..4fe1b05af 100644 --- a/src/Ryujinx/UI/SetupWizard/Pages/SetupKeysPageContext.cs +++ b/src/Ryujinx/UI/SetupWizard/Pages/Keys/SetupKeysPageContext.cs @@ -5,8 +5,6 @@ using CommunityToolkit.Mvvm.Input; using DynamicData; using Gommon; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Systems.SetupWizard; -using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.Utilities; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; @@ -42,7 +40,7 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages } } - private static Result InstallKeys(string directory) + private Result InstallKeys(string directory) { try { @@ -57,18 +55,18 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages ContentManager.InstallKeys(directory, systemDirectory); - NotificationHelper.ShowInformation( + Notifications.NotifyInformation( title: LocaleManager.Instance[LocaleKeys.RyujinxInfo], text: LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallSuccessMessage]); } catch (InvalidFirmwarePackageException ifwpe) { - NotificationHelper.ShowError(ifwpe.Message, waitingExit: true); + Notifications.NotifyError(ifwpe.Message, waitingExit: true); return Result.Failure(NoKeysFoundInFolder.Shared); } catch (MissingKeyException ex) { - NotificationHelper.ShowError(ex.ToString(), waitingExit: true); + Notifications.NotifyError(ex.ToString(), waitingExit: true); return Result.Failure(NoKeysFoundInFolder.Shared); } catch (Exception ex) @@ -80,7 +78,7 @@ namespace Ryujinx.Ava.UI.SetupWizard.Pages LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, directory); } - NotificationHelper.ShowError(message, waitingExit: true); + Notifications.NotifyError(message, waitingExit: true); return Result.Failure(new MessageError(message)); } diff --git a/src/Ryujinx/Systems/SetupWizard/README.md b/src/Ryujinx/UI/SetupWizard/README.md similarity index 100% rename from src/Ryujinx/Systems/SetupWizard/README.md rename to src/Ryujinx/UI/SetupWizard/README.md diff --git a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs index ef0ed6b55..2651140c7 100644 --- a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs +++ b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizard.cs @@ -1,6 +1,5 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Systems.Configuration; -using Ryujinx.Ava.Systems.SetupWizard; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.SetupWizard.Pages; using Ryujinx.Ava.UI.Windows; @@ -9,17 +8,18 @@ using System.Threading.Tasks; namespace Ryujinx.Ava.UI.SetupWizard { public class RyujinxSetupWizard(RyujinxSetupWizardWindow wizardWindow) - : BaseSetupWizard(wizardWindow.WizardPresenter) { private readonly MainWindow _mainWindow = RyujinxApp.MainWindow; private bool _configWasModified; public bool HasFirmware => _mainWindow.ContentManager.GetCurrentFirmwareVersion() != null; + + public NotificationHelper NotificationHelper { get; private set; } - public override async Task Start() + public async Task Start() { - NotificationHelper.SetNotificationManager(wizardWindow); + NotificationHelper = new NotificationHelper(wizardWindow); RyujinxSetupWizardWindow.IsOpen = true; Start: await FirstPage() @@ -39,7 +39,7 @@ namespace Ryujinx.Ava.UI.SetupWizard goto Keys; Return: - NotificationHelper.SetNotificationManager(_mainWindow); + NotificationHelper = null; wizardWindow.Close(); RyujinxSetupWizardWindow.IsOpen = false; @@ -93,6 +93,10 @@ namespace Ryujinx.Ava.UI.SetupWizard return true; } + private SetupWizardPage FirstPage() => new(wizardWindow.WizardPresenter, this, isFirstPage: true); + + private SetupWizardPage NextPage() => new(wizardWindow.WizardPresenter, this); + public void SignalConfigModified() { _configWasModified = true; diff --git a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizardWindow.axaml.cs b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizardWindow.axaml.cs index 61a5295e1..938dbe7eb 100644 --- a/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizardWindow.axaml.cs +++ b/src/Ryujinx/UI/SetupWizard/RyujinxSetupWizardWindow.axaml.cs @@ -1,7 +1,5 @@ using Avalonia.Controls; -using Gommon; using Ryujinx.Ava.Systems.Configuration; -using Ryujinx.Ava.Systems.SetupWizard; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; @@ -31,14 +29,14 @@ namespace Ryujinx.Ava.UI.SetupWizard return Task.CompletedTask; Task windowTask = ShowAsync( - CreateWindow(out BaseSetupWizard wiz), + CreateWindow(out RyujinxSetupWizard wiz), owner ); _ = wiz.Start(); return windowTask; } - public static RyujinxSetupWizardWindow CreateWindow(out BaseSetupWizard setupWizard) + public static RyujinxSetupWizardWindow CreateWindow(out RyujinxSetupWizard setupWizard) { RyujinxSetupWizardWindow window = new(); window.DataContext = setupWizard = new RyujinxSetupWizard(window); diff --git a/src/Ryujinx/Systems/SetupWizard/SetupWizardPage.Builder.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs similarity index 88% rename from src/Ryujinx/Systems/SetupWizard/SetupWizardPage.Builder.cs rename to src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs index 27f516697..cad62f7c1 100644 --- a/src/Ryujinx/Systems/SetupWizard/SetupWizardPage.Builder.cs +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs @@ -2,10 +2,8 @@ using Avalonia; using Avalonia.Controls; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.SetupWizard; -using Ryujinx.Ava.UI.ViewModels; -namespace Ryujinx.Ava.Systems.SetupWizard +namespace Ryujinx.Ava.UI.SetupWizard { public partial class SetupWizardPage { @@ -46,11 +44,11 @@ namespace Ryujinx.Ava.Systems.SetupWizard return this; } - public SetupWizardPage WithContent(out TViewModel boundViewModel) + public SetupWizardPage WithContent(out TViewModel boundViewModel) where TControl : RyujinxControl, new() - where TViewModel : BaseModel, new() + where TViewModel : SetupWizardPageContext, new() { - boundViewModel = new(); + boundViewModel = new() { Notifications = ownerWizard.NotificationHelper }; return WithContent(boundViewModel); } diff --git a/src/Ryujinx/Systems/SetupWizard/SetupWizardPage.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.cs similarity index 90% rename from src/Ryujinx/Systems/SetupWizard/SetupWizardPage.cs rename to src/Ryujinx/UI/SetupWizard/SetupWizardPage.cs index f01794d06..a13eec0dd 100644 --- a/src/Ryujinx/Systems/SetupWizard/SetupWizardPage.cs +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPage.cs @@ -2,15 +2,13 @@ using Avalonia.Controls.Presenters; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.SetupWizard; using Ryujinx.Ava.UI.ViewModels; using System.Threading; using System.Threading.Tasks; -namespace Ryujinx.Ava.Systems.SetupWizard +namespace Ryujinx.Ava.UI.SetupWizard { - public partial class SetupWizardPage(ContentPresenter contentPresenter, bool isFirstPage = false) : BaseModel + public partial class SetupWizardPage(ContentPresenter contentPresenter, RyujinxSetupWizard ownerWizard, bool isFirstPage = false) : BaseModel { private bool? _result; private readonly CancellationTokenSource _cts = new(); diff --git a/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs new file mode 100644 index 000000000..ef49f9b4d --- /dev/null +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs @@ -0,0 +1,13 @@ +using Gommon; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels; + +namespace Ryujinx.Ava.UI.SetupWizard +{ + public abstract class SetupWizardPageContext : BaseModel + { + public NotificationHelper Notifications { get; init; } + + public abstract Result CompleteStep(); + } +} diff --git a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml b/src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml similarity index 96% rename from src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml rename to src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml index 9b451fa0d..acb120018 100644 --- a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml @@ -4,10 +4,10 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:fa="using:Projektanker.Icons.Avalonia" - xmlns:wiz="using:Ryujinx.Ava.Systems.SetupWizard" + xmlns:wiz="using:Ryujinx.Ava.UI.SetupWizard" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:DataType="wiz:SetupWizardPage" - x:Class="Ryujinx.Ava.Systems.SetupWizard.SetupWizardPageView"> + x:Class="Ryujinx.Ava.UI.SetupWizard.SetupWizardPageView"> diff --git a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml.cs b/src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml.cs similarity index 83% rename from src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml.cs rename to src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml.cs index 08b027b99..b7d32d675 100644 --- a/src/Ryujinx/Systems/SetupWizard/SetupWizardPageView.axaml.cs +++ b/src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml.cs @@ -1,6 +1,6 @@ using Ryujinx.Ava.UI.Controls; -namespace Ryujinx.Ava.Systems.SetupWizard +namespace Ryujinx.Ava.UI.SetupWizard { public partial class SetupWizardPageView : RyujinxControl { diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index debbddac9..b563fbb80 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -15,7 +15,6 @@ using Ryujinx.Ava.Systems; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration.UI; -using Ryujinx.Ava.Systems.SetupWizard; using Ryujinx.Ava.UI.Applet; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; @@ -136,7 +135,7 @@ namespace Ryujinx.Ava.UI.Windows { base.OnApplyTemplate(e); - NotificationHelper.SetNotificationManager(this); + NotificationHelper.Shared = new NotificationHelper(this); Executor.ExecuteBackgroundAsync(async () => {