mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-04-23 07:02:56 +00:00
Setup Wizard restructuring
- Remove polymorphic base, this only existed because TKMM has a desktop/switch setup prodecure difference and has 2 implementations of the setup wizard. We only need one. - Remove Systems/UI file split, they're all in Ryujinx.Ava.UI now - made NotificationHelper instance-based to allow you to encapsulate notifications to a window that magically disappear when the window is closed, instead of switching to showing on the main window.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
3
src/Ryujinx/UI/SetupWizard/README.md
Normal file
3
src/Ryujinx/UI/SetupWizard/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Ryubing Setup Wizard
|
||||
|
||||
Directly modified from the code found [here](https://github.com/TKMM-Team/Tkmm/tree/master/src/Tkmm/Wizard).
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
65
src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs
Normal file
65
src/Ryujinx/UI/SetupWizard/SetupWizardPage.Builder.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.SetupWizard
|
||||
{
|
||||
public partial class SetupWizardPage
|
||||
{
|
||||
public SetupWizardPage WithTitle(LocaleKeys title) => WithTitle(LocaleManager.Instance[title]);
|
||||
|
||||
public SetupWizardPage WithTitle(string title)
|
||||
{
|
||||
Title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SetupWizardPage WithContent(LocaleKeys content) => WithContent(LocaleManager.Instance[content]);
|
||||
|
||||
public SetupWizardPage WithContent(object? content)
|
||||
{
|
||||
if (content is StyledElement { Parent: ContentControl parent })
|
||||
{
|
||||
parent.Content = null;
|
||||
}
|
||||
|
||||
Content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SetupWizardPage WithHelpContent(LocaleKeys content) =>
|
||||
WithHelpContent(LocaleManager.Instance[content]);
|
||||
|
||||
public SetupWizardPage WithHelpContent(object? content)
|
||||
{
|
||||
HelpContent = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SetupWizardPage WithContent<TControl>(object? context = null) where TControl : Control, new()
|
||||
{
|
||||
Content = new TControl { DataContext = context };
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public SetupWizardPage WithContent<TControl, TViewModel>(out TViewModel boundViewModel)
|
||||
where TControl : RyujinxControl<TViewModel>, new()
|
||||
where TViewModel : SetupWizardPageContext, new()
|
||||
{
|
||||
boundViewModel = new() { Notifications = ownerWizard.NotificationHelper };
|
||||
|
||||
return WithContent<TControl>(boundViewModel);
|
||||
}
|
||||
|
||||
public SetupWizardPage WithActionContent(LocaleKeys content) =>
|
||||
WithActionContent(LocaleManager.Instance[content]);
|
||||
|
||||
public SetupWizardPage WithActionContent(object? content)
|
||||
{
|
||||
ActionContent = content;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/Ryujinx/UI/SetupWizard/SetupWizardPage.cs
Normal file
59
src/Ryujinx/UI/SetupWizard/SetupWizardPage.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Avalonia.Controls.Presenters;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.SetupWizard
|
||||
{
|
||||
public partial class SetupWizardPage(ContentPresenter contentPresenter, RyujinxSetupWizard ownerWizard, bool isFirstPage = false) : BaseModel
|
||||
{
|
||||
private bool? _result;
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
|
||||
public bool IsFirstPage { get; } = isFirstPage;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string? Title { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial object? Content { get; set; }
|
||||
|
||||
[ObservableProperty] public partial object? HelpContent { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial object? ActionContent { get; set; } = LocaleManager.Instance[LocaleKeys.SetupWizardActionNext];
|
||||
|
||||
[RelayCommand]
|
||||
private void MoveBack()
|
||||
{
|
||||
_result = false;
|
||||
_cts.Cancel();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void MoveNext()
|
||||
{
|
||||
_result = true;
|
||||
_cts.Cancel();
|
||||
}
|
||||
|
||||
public async ValueTask<bool> Show()
|
||||
{
|
||||
contentPresenter.Content = new SetupWizardPageView { ViewModel = this };
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(-1, _cts.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return _result ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs
Normal file
13
src/Ryujinx/UI/SetupWizard/SetupWizardPageContext.cs
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
72
src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml
Normal file
72
src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml
Normal file
@@ -0,0 +1,72 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
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.UI.SetupWizard"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:DataType="wiz:SetupWizardPage"
|
||||
x:Class="Ryujinx.Ava.UI.SetupWizard.SetupWizardPageView">
|
||||
<Grid RowDefinitions="*,Auto" Margin="60">
|
||||
<ScrollViewer>
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<TextBlock Grid.Row="0"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
FontSize="46"
|
||||
Text="{Binding Title}" />
|
||||
|
||||
<ContentPresenter Grid.Row="1"
|
||||
Content="{Binding}"
|
||||
IsVisible="{Binding !#InfoToggle.IsChecked}"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
Margin="0,15,0,0">
|
||||
<ContentPresenter.DataTemplates>
|
||||
<DataTemplate DataType="{x:Type wiz:SetupWizardPage}">
|
||||
<ContentControl Content="{Binding Content}" VerticalAlignment="Stretch"/>
|
||||
</DataTemplate>
|
||||
</ContentPresenter.DataTemplates>
|
||||
</ContentPresenter>
|
||||
|
||||
<Grid Grid.Row="2"
|
||||
ColumnDefinitions="Auto,*"
|
||||
IsVisible="{Binding #InfoToggle.IsChecked}">
|
||||
<StackPanel Spacing="5" VerticalAlignment="Top">
|
||||
<HyperlinkButton NavigateUri="https://discord.gg/PEuzjrFXUA" Content="Join Discord" />
|
||||
</StackPanel>
|
||||
<ContentPresenter Content="{Binding}"
|
||||
Grid.Column="1"
|
||||
Margin="20,0,0,0"
|
||||
TextWrapping="WrapWithOverflow">
|
||||
<ContentPresenter.DataTemplates>
|
||||
<DataTemplate DataType="{x:Type wiz:SetupWizardPage}">
|
||||
<ContentControl Content="{Binding HelpContent}" />
|
||||
</DataTemplate>
|
||||
</ContentPresenter.DataTemplates>
|
||||
</ContentPresenter>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid ColumnDefinitions="Auto,Auto,*" Grid.Row="1">
|
||||
<ToggleButton Name="InfoToggle"
|
||||
Padding="6">
|
||||
<fa:Icon Value="fa-solid fa-circle-info" />
|
||||
</ToggleButton>
|
||||
|
||||
<Button IsVisible="{Binding !IsFirstPage}"
|
||||
Grid.Column="1"
|
||||
Content="{ext:Locale SetupWizardActionBack}"
|
||||
Margin="10,0,0,0"
|
||||
Command="{Binding MoveBackCommand}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Grid.Column="2">
|
||||
<Button Content="{Binding ActionContent}"
|
||||
Command="{Binding MoveNextCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
13
src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml.cs
Normal file
13
src/Ryujinx/UI/SetupWizard/SetupWizardPageView.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.SetupWizard
|
||||
{
|
||||
public partial class SetupWizardPageView : RyujinxControl<SetupWizardPage>
|
||||
{
|
||||
public SetupWizardPageView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user