diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6191c4984..fbae486c3 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,21 +3,21 @@
true
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
+
@@ -48,6 +48,5 @@
-
\ No newline at end of file
diff --git a/distribution/macos/Info.plist b/distribution/macos/Info.plist
index 968814f94..6e068ba2d 100644
--- a/distribution/macos/Info.plist
+++ b/distribution/macos/Info.plist
@@ -44,10 +44,115 @@
public.app-category.games
LSMinimumSystemVersion
11.0
+ UTExportedTypeDeclarations
+
+
+ UTTypeDescription
+ Extensible Application Markup Language
+ UTTypeConformsTo
+
+ public.xml
+
+ UTTypeIdentifier
+ com.ryujinx.xaml
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ xaml
+
+
+
+
+ UTTypeDescription
+ Nintendo Submission Package
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeIdentifier
+ com.ryujinx.nsp
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ nsp
+
+
+
+
+ UTTypeDescription
+ Nintendo Switch Cartridge
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeIdentifier
+ com.ryujinx.xci
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ xci
+
+
+
+
+ UTTypeDescription
+ Nintendo Content Archive
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeIdentifier
+ com.ryujinx.nca
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ nca
+
+
+
+
+ UTTypeDescription
+ Nintendo Relocatable Object
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeIdentifier
+ com.ryujinx.nro
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ nro
+
+
+
+
+ UTTypeDescription
+ Nintendo Shared Object
+ UTTypeConformsTo
+
+ public.data
+
+ UTTypeIdentifier
+ com.ryujinx.nso
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ nso
+
+
+
+
LSEnvironment
- COMPlus_DefaultStackSize
+ DOTNET_DefaultStackSize
200000
-
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/App.axaml b/src/Ryujinx.Ava/App.axaml
index 72bc0deee..eab318b7b 100644
--- a/src/Ryujinx.Ava/App.axaml
+++ b/src/Ryujinx.Ava/App.axaml
@@ -3,7 +3,15 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sty="using:FluentAvalonia.Styling">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/App.axaml.cs b/src/Ryujinx.Ava/App.axaml.cs
index 4ecc424a6..031e7e447 100644
--- a/src/Ryujinx.Ava/App.axaml.cs
+++ b/src/Ryujinx.Ava/App.axaml.cs
@@ -3,7 +3,6 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using Avalonia.Threading;
-using FluentAvalonia.Styling;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows;
@@ -24,6 +23,11 @@ namespace Ryujinx.Ava
Name = $"Ryujinx {Program.Version}";
AvaloniaXamlLoader.Load(this);
+
+ if (OperatingSystem.IsMacOS())
+ {
+ Process.Start("/usr/bin/defaults", "write org.ryujinx.Ryujinx ApplePressAndHoldEnabled -bool false");
+ }
}
public override void OnFrameworkInitializationCompleted()
@@ -89,8 +93,6 @@ namespace Ryujinx.Ava
string themePath = ConfigurationState.Instance.Ui.CustomThemePath;
bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme;
- const string BaseStyleUrl = "avares://Ryujinx.Ava/Assets/Styles/Base{0}.xaml";
-
if (string.IsNullOrWhiteSpace(baseStyle))
{
ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark";
@@ -98,31 +100,12 @@ namespace Ryujinx.Ava
baseStyle = ConfigurationState.Instance.Ui.BaseStyle;
}
- var theme = AvaloniaLocator.Current.GetService();
-
- theme.RequestedTheme = baseStyle;
-
- var currentStyles = this.Styles;
-
- // Remove all styles except the base style.
- if (currentStyles.Count > 1)
+ RequestedThemeVariant = baseStyle switch
{
- currentStyles.RemoveRange(1, currentStyles.Count - 1);
- }
-
- IStyle newStyles = null;
-
- // Load requested style, and fallback to Dark theme if loading failed.
- try
- {
- newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, baseStyle), UriKind.Absolute));
- }
- catch (XamlLoadException)
- {
- newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, "Dark"), UriKind.Absolute));
- }
-
- currentStyles.Add(newStyles);
+ "Light" => ThemeVariant.Light,
+ "Dark" => ThemeVariant.Dark,
+ _ => ThemeVariant.Default
+ };
if (enableCustomTheme)
{
@@ -133,7 +116,7 @@ namespace Ryujinx.Ava
var themeContent = File.ReadAllText(themePath);
var customStyle = AvaloniaRuntimeXamlLoader.Parse(themeContent);
- currentStyles.Add(customStyle);
+ Styles.Add(customStyle);
}
catch (Exception ex)
{
diff --git a/src/Ryujinx.Ava/AppHost.cs b/src/Ryujinx.Ava/AppHost.cs
index 786b45070..a8388e9cd 100644
--- a/src/Ryujinx.Ava/AppHost.cs
+++ b/src/Ryujinx.Ava/AppHost.cs
@@ -3,6 +3,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
+using Avalonia.Rendering;
using Avalonia.Threading;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy;
@@ -54,6 +55,7 @@ using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using Image = SixLabors.ImageSharp.Image;
using InputManager = Ryujinx.Input.HLE.InputManager;
+using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
using Key = Ryujinx.Input.Key;
using MouseButton = Ryujinx.Input.MouseButton;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
@@ -167,9 +169,9 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.HideCursor.Event += HideCursorState_Changed;
- _topLevel.PointerMoved += TopLevel_PointerEnterOrMoved;
- _topLevel.PointerEnter += TopLevel_PointerEnterOrMoved;
- _topLevel.PointerLeave += TopLevel_PointerLeave;
+ _topLevel.PointerMoved += TopLevel_PointerEnteredOrMoved;
+ _topLevel.PointerEntered += TopLevel_PointerEnteredOrMoved;
+ _topLevel.PointerExited += TopLevel_PointerExited;
if (OperatingSystem.IsWindows())
{
@@ -194,26 +196,23 @@ namespace Ryujinx.Ava
_gpuDoneEvent = new ManualResetEvent(false);
}
- private void TopLevel_PointerEnterOrMoved(object sender, PointerEventArgs e)
+ private void TopLevel_PointerEnteredOrMoved(object sender, PointerEventArgs e)
{
if (sender is MainWindow window)
{
_lastCursorMoveTime = Stopwatch.GetTimestamp();
- if (RendererHost.EmbeddedWindow.TransformedBounds != null)
- {
- var point = e.GetCurrentPoint(window).Position;
- var bounds = RendererHost.EmbeddedWindow.TransformedBounds.Value.Clip;
+ var point = e.GetCurrentPoint(window).Position;
+ var bounds = RendererHost.EmbeddedWindow.Bounds;
- _isCursorInRenderer = point.X >= bounds.X &&
- point.X <= bounds.Width + bounds.X &&
- point.Y >= bounds.Y &&
- point.Y <= bounds.Height + bounds.Y;
- }
+ _isCursorInRenderer = point.X >= bounds.X &&
+ point.X <= bounds.Width + bounds.X &&
+ point.Y >= bounds.Y &&
+ point.Y <= bounds.Height + bounds.Y;
}
}
- private void TopLevel_PointerLeave(object sender, PointerEventArgs e)
+ private void TopLevel_PointerExited(object sender, PointerEventArgs e)
{
_isCursorInRenderer = false;
}
@@ -265,7 +264,7 @@ namespace Ryujinx.Ava
{
if (_renderer != null)
{
- double scale = _topLevel.PlatformImpl.RenderScaling;
+ double scale = _topLevel.RenderScaling;
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
}
@@ -359,7 +358,7 @@ namespace Ryujinx.Ava
_viewModel.SetUiProgressHandlers(Device);
- RendererHost.SizeChanged += Window_SizeChanged;
+ RendererHost.BoundsChanged += Window_BoundsChanged;
_isActive = true;
@@ -469,9 +468,9 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAntiAliasing;
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event -= UpdateColorSpacePassthrough;
- _topLevel.PointerMoved -= TopLevel_PointerEnterOrMoved;
- _topLevel.PointerEnter -= TopLevel_PointerEnterOrMoved;
- _topLevel.PointerLeave -= TopLevel_PointerLeave;
+ _topLevel.PointerMoved -= TopLevel_PointerEnteredOrMoved;
+ _topLevel.PointerEntered -= TopLevel_PointerEnteredOrMoved;
+ _topLevel.PointerExited -= TopLevel_PointerExited;
_gpuCancellationTokenSource.Cancel();
_gpuCancellationTokenSource.Dispose();
@@ -849,7 +848,7 @@ namespace Ryujinx.Ava
return deviceDriver;
}
- private void Window_SizeChanged(object sender, Size e)
+ private void Window_BoundsChanged(object sender, Size e)
{
Width = (int)e.Width;
Height = (int)e.Height;
@@ -899,7 +898,7 @@ namespace Ryujinx.Ava
Width = (int)RendererHost.Bounds.Width;
Height = (int)RendererHost.Bounds.Height;
- _renderer.Window.SetSize((int)(Width * _topLevel.PlatformImpl.RenderScaling), (int)(Height * _topLevel.PlatformImpl.RenderScaling));
+ _renderer.Window.SetSize((int)(Width * _topLevel.RenderScaling), (int)(Height * _topLevel.RenderScaling));
_chrono.Start();
diff --git a/src/Ryujinx.Ava/Assets/Styles/BaseDark.xaml b/src/Ryujinx.Ava/Assets/Styles/BaseDark.xaml
deleted file mode 100644
index c7f6266fb..000000000
--- a/src/Ryujinx.Ava/Assets/Styles/BaseDark.xaml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Test Check
-
-
-
-
-
-
-
-
-
- #008AA8
-
-
- #FF00C3E3
- #FF99b000
- #FF006d7d
- #FF00525E
- #FF00dbff
- #FF19dfff
- #FF33e3ff
- #FF00FABB
- #FF2D2D2D
- #FF505050
- #FFFFFFFF
- #FFFFFFFF
- #FFFFFFFF
- #3D3D3D
- #0FFFFFFF
- #1EFFFFFF
- #A0FFFFFF
-
-
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/Assets/Styles/BaseLight.xaml b/src/Ryujinx.Ava/Assets/Styles/BaseLight.xaml
deleted file mode 100644
index 70cb051cf..000000000
--- a/src/Ryujinx.Ava/Assets/Styles/BaseLight.xaml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Test Check
-
-
-
-
-
-
-
-
-
- #FF00C3E3
- #FFe8e8e8
- #FF00FABB
- #FFF0F0F0
- #FFd6d6d6
- #FFFFFFFF
- #FFFFFFFF
- #FF000000
- #C1C1C1
- #b3ffffff
- #80cccccc
- #A0000000
-
-
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/Assets/Styles/Styles.xaml b/src/Ryujinx.Ava/Assets/Styles/Styles.xaml
index 681b4feaf..146e60b5e 100644
--- a/src/Ryujinx.Ava/Assets/Styles/Styles.xaml
+++ b/src/Ryujinx.Ava/Assets/Styles/Styles.xaml
@@ -3,17 +3,20 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
-
+
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
40 0 40 0
0 5 0 5
5 0 5 0
- #00000000
- #FF00C3E3
- #FF00C3E3
- #FF00C3E3
- #FF00C3E3
- #FF00C3E3
- #FF00C3E3
- #FF00C3E3
- #FF00FABB
- #FF2D2D2D
- #FF505050
- #FF2EEAC9
- #FFFF4554
- #0FFFFFFF
- #1EFFFFFF
- #A0FFFFFF
15
8
10
diff --git a/src/Ryujinx.Ava/Assets/Styles/Themes.xaml b/src/Ryujinx.Ava/Assets/Styles/Themes.xaml
new file mode 100644
index 000000000..0f323f84b
--- /dev/null
+++ b/src/Ryujinx.Ava/Assets/Styles/Themes.xaml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FFe8e8e8
+ #FF00FABB
+ #FFF0F0F0
+ #FFd6d6d6
+ #FFFFFFFF
+ #FFFFFFFF
+ #FF000000
+ #C1C1C1
+ #b3ffffff
+ #80cccccc
+ #A0000000
+ #FF2EEAC9
+ #FFFF4554
+
+
+
+
+
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FF00C3E3
+ #FFe8e8e8
+ #FF00FABB
+ #FFF0F0F0
+ #FFd6d6d6
+ #FFFFFFFF
+ #FFFFFFFF
+ #FF000000
+ #C1C1C1
+ #b3ffffff
+ #80cccccc
+ #A0000000
+
+
+
+
+
+ #008AA8
+ #FF00C3E3
+ #FF99b000
+ #FF006d7d
+ #FF00525E
+ #FF00dbff
+ #FF19dfff
+ #FF33e3ff
+ #FF00FABB
+ #FF2D2D2D
+ #FF505050
+ #FFFFFFFF
+ #FFFFFFFF
+ #FFFFFFFF
+ #3D3D3D
+ #0FFFFFFF
+ #1EFFFFFF
+ #A0FFFFFF
+
+
+
diff --git a/src/Ryujinx.Ava/Common/ApplicationHelper.cs b/src/Ryujinx.Ava/Common/ApplicationHelper.cs
index d28d5aac1..9e4757538 100644
--- a/src/Ryujinx.Ava/Common/ApplicationHelper.cs
+++ b/src/Ryujinx.Ava/Common/ApplicationHelper.cs
@@ -1,5 +1,5 @@
-using Avalonia.Controls;
using Avalonia.Controls.Notifications;
+using Avalonia.Platform.Storage;
using Avalonia.Threading;
using LibHac;
using LibHac.Account;
@@ -143,14 +143,20 @@ namespace Ryujinx.Ava.Common
}
}
- public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
+ public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
{
- OpenFolderDialog folderDialog = new()
+ var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
- };
+ AllowMultiple = false
+ });
- string destination = await folderDialog.ShowAsync(_owner);
+ if (result.Count == 0)
+ {
+ return;
+ }
+
+ var destination = result[0].Path.LocalPath;
var cancellationToken = new CancellationTokenSource();
UpdateWaitWindow waitingDialog = new(
@@ -158,148 +164,145 @@ namespace Ryujinx.Ava.Common
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
cancellationToken);
- if (!string.IsNullOrWhiteSpace(destination))
+ Thread extractorThread = new(() =>
{
- Thread extractorThread = new(() =>
+ Dispatcher.UIThread.Post(waitingDialog.Show);
+
+ using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
+
+ Nca mainNca = null;
+ Nca patchNca = null;
+
+ string extension = Path.GetExtension(titleFilePath).ToLower();
+ if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
{
- Dispatcher.UIThread.Post(waitingDialog.Show);
+ PartitionFileSystem pfs;
- using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
-
- Nca mainNca = null;
- Nca patchNca = null;
-
- string extension = Path.GetExtension(titleFilePath).ToLower();
- if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
+ if (extension == ".xci")
{
- PartitionFileSystem pfs;
+ pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
+ }
+ else
+ {
+ pfs = new PartitionFileSystem(file.AsStorage());
+ }
- if (extension == ".xci")
+ foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
+ {
+ using var ncaFile = new UniqueRef();
+
+ pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
+
+ Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
+ if (nca.Header.ContentType == NcaContentType.Program)
{
- pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
- }
- else
- {
- pfs = new PartitionFileSystem(file.AsStorage());
- }
-
- foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
- {
- using var ncaFile = new UniqueRef();
-
- pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
- if (nca.Header.ContentType == NcaContentType.Program)
+ int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
+ if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
{
- int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
- if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
- {
- patchNca = nca;
- }
- else
- {
- mainNca = nca;
- }
+ patchNca = nca;
+ }
+ else
+ {
+ mainNca = nca;
}
}
}
- else if (extension == ".nca")
- {
- mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
- }
-
- if (mainNca == null)
- {
- Logger.Error?.Print(LogClass.Application, "Extraction failure. The main NCA was not present in the selected file");
-
- Dispatcher.UIThread.InvokeAsync(async () =>
- {
- waitingDialog.Close();
-
- await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
- });
-
- return;
- }
-
- (Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
- if (updatePatchNca != null)
- {
- patchNca = updatePatchNca;
- }
-
- int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType);
-
- try
- {
- bool sectionExistsInPatch = false;
- if (patchNca != null)
- {
- sectionExistsInPatch = patchNca.CanOpenSection(index);
- }
-
- IFileSystem ncaFileSystem = sectionExistsInPatch ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid)
- : mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
-
- FileSystemClient fsClient = _horizonClient.Fs;
-
- string source = DateTime.Now.ToFileTime().ToString()[10..];
- string output = DateTime.Now.ToFileTime().ToString()[10..];
-
- using var uniqueSourceFs = new UniqueRef(ncaFileSystem);
- using var uniqueOutputFs = new UniqueRef(new LocalFileSystem(destination));
-
- fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
- fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
-
- (Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/", cancellationToken.Token);
-
- if (!canceled)
- {
- if (resultCode.Value.IsFailure())
- {
- Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
-
- Dispatcher.UIThread.InvokeAsync(async () =>
- {
- waitingDialog.Close();
-
- await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
- });
- }
- else if (resultCode.Value.IsSuccess())
- {
- Dispatcher.UIThread.Post(waitingDialog.Close);
-
- NotificationHelper.Show(
- LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
- $"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}",
- NotificationType.Information);
- }
- }
-
- fsClient.Unmount(source.ToU8Span());
- fsClient.Unmount(output.ToU8Span());
- }
- catch (ArgumentException ex)
- {
- Logger.Error?.Print(LogClass.Application, $"{ex.Message}");
-
- Dispatcher.UIThread.InvokeAsync(async () =>
- {
- waitingDialog.Close();
-
- await ContentDialogHelper.CreateErrorDialog(ex.Message);
- });
- }
- })
+ }
+ else if (extension == ".nca")
{
- Name = "GUI.NcaSectionExtractorThread",
- IsBackground = true,
- };
- extractorThread.Start();
- }
+ mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
+ }
+
+ if (mainNca == null)
+ {
+ Logger.Error?.Print(LogClass.Application, "Extraction failure. The main NCA was not present in the selected file");
+
+ Dispatcher.UIThread.InvokeAsync(async () =>
+ {
+ waitingDialog.Close();
+
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
+ });
+
+ return;
+ }
+
+ (Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
+ if (updatePatchNca != null)
+ {
+ patchNca = updatePatchNca;
+ }
+
+ int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType);
+
+ try
+ {
+ bool sectionExistsInPatch = false;
+ if (patchNca != null)
+ {
+ sectionExistsInPatch = patchNca.CanOpenSection(index);
+ }
+
+ IFileSystem ncaFileSystem = sectionExistsInPatch ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid)
+ : mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
+
+ FileSystemClient fsClient = _horizonClient.Fs;
+
+ string source = DateTime.Now.ToFileTime().ToString()[10..];
+ string output = DateTime.Now.ToFileTime().ToString()[10..];
+
+ using var uniqueSourceFs = new UniqueRef(ncaFileSystem);
+ using var uniqueOutputFs = new UniqueRef(new LocalFileSystem(destination));
+
+ fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
+ fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
+
+ (Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/", cancellationToken.Token);
+
+ if (!canceled)
+ {
+ if (resultCode.Value.IsFailure())
+ {
+ Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
+
+ Dispatcher.UIThread.InvokeAsync(async () =>
+ {
+ waitingDialog.Close();
+
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
+ });
+ }
+ else if (resultCode.Value.IsSuccess())
+ {
+ Dispatcher.UIThread.Post(waitingDialog.Close);
+
+ NotificationHelper.Show(
+ LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
+ $"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}",
+ NotificationType.Information);
+ }
+ }
+
+ fsClient.Unmount(source.ToU8Span());
+ fsClient.Unmount(output.ToU8Span());
+ }
+ catch (ArgumentException ex)
+ {
+ Logger.Error?.Print(LogClass.Application, $"{ex.Message}");
+
+ Dispatcher.UIThread.InvokeAsync(async () =>
+ {
+ waitingDialog.Close();
+
+ await ContentDialogHelper.CreateErrorDialog(ex.Message);
+ });
+ }
+ })
+ {
+ Name = "GUI.NcaSectionExtractorThread",
+ IsBackground = true,
+ };
+ extractorThread.Start();
}
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
diff --git a/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs b/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
index f12d0214b..856ed6f7e 100644
--- a/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
+++ b/src/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
@@ -31,7 +31,6 @@ namespace Ryujinx.Ava.Input
_control.KeyDown += OnKeyPress;
_control.KeyUp += OnKeyRelease;
_control.TextInput += Control_TextInput;
- _control.AddHandler(InputElement.TextInputEvent, Control_LastChanceTextInput, RoutingStrategies.Bubble);
}
private void Control_TextInput(object sender, TextInputEventArgs e)
@@ -39,12 +38,6 @@ namespace Ryujinx.Ava.Input
TextInput?.Invoke(this, e.Text);
}
- private void Control_LastChanceTextInput(object sender, TextInputEventArgs e)
- {
- // Swallow event
- e.Handled = true;
- }
-
public event Action OnGamepadConnected
{
add { }
diff --git a/src/Ryujinx.Ava/Program.cs b/src/Ryujinx.Ava/Program.cs
index 5241f91f8..86f38c347 100644
--- a/src/Ryujinx.Ava/Program.cs
+++ b/src/Ryujinx.Ava/Program.cs
@@ -59,15 +59,12 @@ namespace Ryujinx.Ava
{
EnableMultiTouch = true,
EnableIme = true,
- UseEGL = false,
- UseGpu = true,
+ RenderingMode = new[] { X11RenderingMode.Glx, X11RenderingMode.Software },
})
.With(new Win32PlatformOptions
{
- EnableMultitouch = true,
- UseWgl = false,
- AllowEglInitialization = false,
- CompositionBackdropCornerRadius = 8.0f,
+ WinUICompositionBackdropCornerRadius = 8.0f,
+ RenderingMode = new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software },
})
.UseSkia();
}
diff --git a/src/Ryujinx.Ava/Ryujinx.Ava.csproj b/src/Ryujinx.Ava/Ryujinx.Ava.csproj
index 1fac5400e..a4c1ebf16 100644
--- a/src/Ryujinx.Ava/Ryujinx.Ava.csproj
+++ b/src/Ryujinx.Ava/Ryujinx.Ava.csproj
@@ -10,6 +10,8 @@
Ryujinx.Ava
Ryujinx.ico
true
+ true
+ app.manifest
@@ -26,7 +28,7 @@
-
+
@@ -34,7 +36,6 @@
-
@@ -97,10 +98,7 @@
Designer
-
- MSBuild:Compile
-
-
+
MSBuild:Compile
@@ -123,8 +121,7 @@
-
-
+
diff --git a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml
index 211b47254..a70fc8d44 100644
--- a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml
+++ b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml
@@ -38,7 +38,7 @@
Grid.Column="1"
Margin="10"
VerticalAlignment="Stretch"
- Text="{Binding Message}"
+ Text="{ReflectionBinding Message}"
TextWrapping="Wrap" />
diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml
index 29547f5fe..93638fc53 100644
--- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml
+++ b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml
@@ -2,7 +2,9 @@
x:Class="Ryujinx.Ava.UI.Controls.ApplicationContextMenu"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale">
+ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ x:DataType="viewModels:MainWindowViewModel">
diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs
index 77b4f5207..f54e9df8f 100644
--- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs
@@ -299,7 +299,11 @@ namespace Ryujinx.Ava.UI.Controls
if (viewModel?.SelectedApplication != null)
{
- await ApplicationHelper.ExtractSection(NcaSectionType.Code, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+ await ApplicationHelper.ExtractSection(
+ viewModel.StorageProvider,
+ NcaSectionType.Code,
+ viewModel.SelectedApplication.Path,
+ viewModel.SelectedApplication.TitleName);
}
}
@@ -309,7 +313,11 @@ namespace Ryujinx.Ava.UI.Controls
if (viewModel?.SelectedApplication != null)
{
- await ApplicationHelper.ExtractSection(NcaSectionType.Data, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+ await ApplicationHelper.ExtractSection(
+ viewModel.StorageProvider,
+ NcaSectionType.Data,
+ viewModel.SelectedApplication.Path,
+ viewModel.SelectedApplication.TitleName);
}
}
@@ -319,7 +327,11 @@ namespace Ryujinx.Ava.UI.Controls
if (viewModel?.SelectedApplication != null)
{
- await ApplicationHelper.ExtractSection(NcaSectionType.Logo, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+ await ApplicationHelper.ExtractSection(
+ viewModel.StorageProvider,
+ NcaSectionType.Logo,
+ viewModel.SelectedApplication.Path,
+ viewModel.SelectedApplication.TitleName);
}
}
diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml
index 3d55793f9..214fc0755 100644
--- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml
+++ b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml
@@ -11,7 +11,9 @@
d:DesignHeight="450"
d:DesignWidth="800"
Focusable="True"
- mc:Ignorable="d">
+ mc:Ignorable="d"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ x:DataType="viewModels:MainWindowViewModel">
@@ -27,7 +29,7 @@
VerticalAlignment="Stretch"
ContextFlyout="{StaticResource ApplicationContextMenu}"
DoubleTapped="GameList_DoubleTapped"
- Items="{Binding AppsObservableList}"
+ ItemsSource="{Binding AppsObservableList}"
SelectionChanged="GameList_SelectionChanged">
@@ -43,8 +45,8 @@
-
@@ -54,10 +56,10 @@
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
- Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
- Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
- Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
- Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
+ Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
+ Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
+ Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
+ Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
ClipToBounds="True"
CornerRadius="4">
@@ -76,9 +78,9 @@
Margin="0,10,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
- IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
+ IsVisible="{ReflectionBinding $parent[UserControl].DataContext.ShowNames}">
+ mc:Ignorable="d"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ x:DataType="viewModels:MainWindowViewModel">
@@ -27,7 +29,7 @@
VerticalAlignment="Stretch"
ContextFlyout="{StaticResource ApplicationContextMenu}"
DoubleTapped="GameList_DoubleTapped"
- Items="{Binding AppsObservableList}"
+ ItemsSource="{Binding AppsObservableList}"
SelectionChanged="GameList_SelectionChanged">
@@ -39,8 +41,8 @@
-
@@ -65,10 +67,10 @@
Grid.RowSpan="3"
Grid.Column="0"
Margin="0"
- Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
- Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
- Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
- Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
+ Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
+ Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
+ Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
+ Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
CommandParameterProperty =
- AvaloniaProperty.Register(nameof(CommandParameter));
-
- public static readonly DirectProperty CommandProperty =
- AvaloniaProperty.RegisterDirect(nameof(Command),
- control => control.Command, (control, command) => control.Command = command, enableDataValidation: true);
-
- public static readonly StyledProperty HotKeyProperty = HotKeyManager.HotKeyProperty.AddOwner
@@ -750,7 +749,7 @@
diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs
index 19009f5f2..351297060 100644
--- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs
@@ -31,8 +31,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
if (visual is ToggleButton button && visual is not CheckBox)
{
- button.Checked += Button_Checked;
- button.Unchecked += Button_Unchecked;
+ button.IsCheckedChanged += Button_IsCheckedChanged;
}
}
}
@@ -47,48 +46,56 @@ namespace Ryujinx.Ava.UI.Views.Input
}
}
- private void Button_Checked(object sender, RoutedEventArgs e)
+ private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton button)
{
- if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
+ if ((bool)button.IsChecked)
{
- return;
- }
-
- bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
-
- if (_currentAssigner == null && (bool)button.IsChecked)
- {
- _currentAssigner = new ButtonKeyAssigner(button);
-
- FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
-
- PointerPressed += MouseClick;
-
- IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
- IButtonAssigner assigner = CreateButtonAssigner(isStick);
-
- _currentAssigner.ButtonAssigned += (sender, e) =>
+ if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
{
- if (e.IsAssigned)
- {
- ViewModel.IsModified = true;
- }
- };
+ return;
+ }
- _currentAssigner.GetInputAndAssign(assigner, keyboard);
+ bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
+
+ if (_currentAssigner == null)
+ {
+ _currentAssigner = new ButtonKeyAssigner(button);
+
+ this.Focus(NavigationMethod.Pointer);
+
+ PointerPressed += MouseClick;
+
+ IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
+ IButtonAssigner assigner = CreateButtonAssigner(isStick);
+
+ _currentAssigner.ButtonAssigned += (sender, e) =>
+ {
+ if (e.IsAssigned)
+ {
+ ViewModel.IsModified = true;
+ }
+ };
+
+ _currentAssigner.GetInputAndAssign(assigner, keyboard);
+ }
+ else
+ {
+ if (_currentAssigner != null)
+ {
+ ToggleButton oldButton = _currentAssigner.ToggledButton;
+
+ _currentAssigner.Cancel();
+ _currentAssigner = null;
+ button.IsChecked = false;
+ }
+ }
}
else
{
- if (_currentAssigner != null)
- {
- ToggleButton oldButton = _currentAssigner.ToggledButton;
-
- _currentAssigner.Cancel();
- _currentAssigner = null;
- button.IsChecked = false;
- }
+ _currentAssigner?.Cancel();
+ _currentAssigner = null;
}
}
}
@@ -120,12 +127,6 @@ namespace Ryujinx.Ava.UI.Views.Input
return assigner;
}
- private void Button_Unchecked(object sender, RoutedEventArgs e)
- {
- _currentAssigner?.Cancel();
- _currentAssigner = null;
- }
-
private void MouseClick(object sender, PointerPressedEventArgs e)
{
bool shouldUnbind = false;
diff --git a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml
index b18324379..71d5d7460 100644
--- a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml
@@ -8,7 +8,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
- x:CompileBindings="True"
x:DataType="viewModels:MotionInputViewModel"
Focusable="True">
diff --git a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml
index 3882ebe21..16190d391 100644
--- a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml
@@ -8,7 +8,6 @@
mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
x:DataType="viewModels:RumbleInputViewModel"
- x:CompileBindings="True"
Focusable="True">
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
index d5b5efcdd..30358adab 100644
--- a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
@@ -7,8 +7,7 @@
mc:Ignorable="d"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:DataType="viewModels:MainWindowViewModel"
- x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView"
- x:CompileBindings="True">
+ x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView">
@@ -25,12 +24,12 @@
@@ -57,35 +56,75 @@
-
+
-
-
-
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
-
-
+
+
@@ -113,7 +152,7 @@
InputGesture="Escape"
IsEnabled="{Binding IsGameRunning}"
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
-
+
@@ -138,8 +177,8 @@
-
-
+
+
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
index ae52f0719..af8c4dab9 100644
--- a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
@@ -30,8 +30,8 @@ namespace Ryujinx.Ava.UI.Views.Main
{
InitializeComponent();
- ToggleFileTypesMenuItem.Items = GenerateToggleFileTypeItems();
- ChangeLanguageMenuItem.Items = GenerateLanguageMenuItems();
+ ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
+ ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
}
private CheckBox[] GenerateToggleFileTypeItems()
@@ -45,7 +45,7 @@ namespace Ryujinx.Ava.UI.Views.Main
{
Content = $".{fileName}",
IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes),
- Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName)),
+ Command = MiniCommand.Create(() => Window.ToggleFileType(fileName)),
});
}
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
index 167056954..58e06a1c2 100644
--- a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
@@ -8,7 +8,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
- x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel">
@@ -46,7 +45,7 @@
Margin="0,0,5,0"
VerticalAlignment="Center"
Background="Transparent"
- Command="{ReflectionBinding LoadApplications}">
+ Click="Refresh_OnClick">
@@ -93,6 +92,7 @@
Height="12"
Margin="0"
BorderBrush="Gray"
+ Background="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
-
-
+ IsVisible="{Binding !ShowLoadProgress}"
+ Background="Transparent"
+ BorderThickness="0"
+ CornerRadius="0">
+
+
+
+
+
+
-
-
+
+
-
\ No newline at end of file
+
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
index 0640869c1..a0acc2779 100644
--- a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
@@ -48,5 +49,10 @@ namespace Ryujinx.Ava.UI.Views.Main
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
}
+
+ private void Refresh_OnClick(object sender, RoutedEventArgs e)
+ {
+ Window.LoadApplications();
+ }
}
}
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
index f7dbf2b21..f5a177424 100644
--- a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
@@ -9,7 +9,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls"
- x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel">
@@ -23,7 +22,7 @@
MinWidth="40"
Margin="5,2,0,2"
VerticalAlignment="Stretch"
- Command="{ReflectionBinding SetListMode}"
+ Command="{Binding SetListMode}"
IsEnabled="{Binding IsGrid}">
-
-
+
-
-
+
+
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
index e98b963c1..c74d3dd57 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
- x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel">
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
index 670de69c6..9dc67dadb 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
@@ -1,4 +1,4 @@
-
@@ -54,7 +53,7 @@
HorizontalContentAlignment="Left"
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
SelectedIndex="{Binding PreferredGpuIndex}"
- Items="{Binding AvailableGpus}"/>
+ ItemsSource="{Binding AvailableGpus}"/>
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
index 361125bfe..a53c1dfe4 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
@@ -1,4 +1,4 @@
-
@@ -17,7 +16,7 @@
-
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
index 948e7181f..0fc9ea1bb 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
@@ -8,7 +8,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
- x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel">
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
index ab8a7f6d1..6ce1bb94f 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
- x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel">
@@ -37,7 +36,7 @@
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
index cc60ef24d..e6f7c6e46 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
@@ -3,12 +3,15 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
- x:CompileBindings="True"
- x:DataType="viewModels:SettingsViewModel"
- mc:Ignorable="d">
+ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+ mc:Ignorable="d"
+ x:DataType="viewModels:SettingsViewModel">
+
+
+
@@ -24,18 +27,24 @@
HorizontalAlignment="Stretch"
Orientation="Vertical"
Spacing="10">
-
-
-
+
+
+
+ Text="{locale:Locale SettingsTabSystemSystemRegion}"
+ Width="250" />
+ ToolTip.Tip="{locale:Locale RegionTooltip}"
+ HorizontalContentAlignment="Left"
+ Width="350">
@@ -59,17 +68,19 @@
-
+
+ ToolTip.Tip="{locale:Locale LanguageTooltip}"
+ Width="250" />
+ ToolTip.Tip="{locale:Locale LanguageTooltip}"
+ HorizontalContentAlignment="Left"
+ Width="350">
@@ -126,63 +137,84 @@
-
+
+ ToolTip.Tip="{locale:Locale TimezoneTooltip}"
+ Width="250" />
+ ToolTip.Tip="{locale:Locale TimezoneTooltip}"
+ ValueMemberBinding="{Binding Mode=OneWay, Converter={StaticResource TimeZone}}" />
-
+
+ ToolTip.Tip="{locale:Locale TimeTooltip}"
+ Width="250"/>
+ ToolTip.Tip="{locale:Locale TimeTooltip}"
+ Width="350" />
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
+
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
index 4acf2f44c..216561dc9 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
@@ -1,9 +1,5 @@
using Avalonia.Controls;
-using Avalonia.Data;
-using Avalonia.Data.Converters;
using Ryujinx.Ava.UI.ViewModels;
-using System;
-using System.Linq;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.Views.Settings
@@ -15,15 +11,6 @@ namespace Ryujinx.Ava.UI.Views.Settings
public SettingsSystemView()
{
InitializeComponent();
-
- FuncMultiValueConverter converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
- MultiBinding tzMultiBinding = new() { Converter = converter };
-
- tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
- tzMultiBinding.Bindings.Add(new Binding("Location"));
- tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
-
- TimeZoneBox.ValueMemberBinding = tzMultiBinding;
}
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -39,13 +26,11 @@ namespace Ryujinx.Ava.UI.Views.Settings
}
}
- private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
+ private void TimeZoneBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
{
- {
- ViewModel.ValidateAndSetTimeZone(timeZone.Location);
- }
+ ViewModel.ValidateAndSetTimeZone(timeZone.Location);
}
}
}
diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
index c92d56728..b7471d385 100644
--- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
- x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel">
@@ -66,7 +65,7 @@
+ ItemsSource="{Binding GameDirectories}">
-
diff --git a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
index b9f51fdc7..65fbd4434 100644
--- a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
@@ -9,7 +9,6 @@
Focusable="True"
mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView"
- x:CompileBindings="True"
x:DataType="viewModles:UserProfileImageSelectorViewModel"
Width="500"
d:DesignWidth="500">
diff --git a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
index 26b77dcdc..e9bf4408c 100644
--- a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
+using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
@@ -10,6 +11,7 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.HLE.FileSystem;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
+using System.Collections.Generic;
using System.IO;
using Image = SixLabors.ImageSharp.Image;
@@ -63,33 +65,25 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e)
{
- OpenFileDialog dialog = new();
- dialog.Filters.Add(new FileDialogFilter
+ var window = this.GetVisualRoot() as Window;
+ var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
- Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
- Extensions = { "jpg", "jpeg", "png", "bmp" },
- });
- dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
- dialog.Filters.Add(new FileDialogFilter { Name = "PNG", Extensions = { "png" } });
- dialog.Filters.Add(new FileDialogFilter { Name = "BMP", Extensions = { "bmp" } });
-
- dialog.AllowMultiple = false;
-
- string[] image = await dialog.ShowAsync(((TopLevel)_parent.GetVisualRoot()) as Window);
-
- if (image != null)
- {
- if (image.Length > 0)
+ AllowMultiple = false,
+ FileTypeFilter = new List
{
- string imageFile = image[0];
-
- _profile.Image = ProcessProfileImage(File.ReadAllBytes(imageFile));
-
- if (_profile.Image != null)
+ new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
{
- _parent.GoBack();
+ Patterns = new[] { "*.jpg", "*.jpeg", "*.png", "*.bmp" },
+ AppleUniformTypeIdentifiers = new[] { "public.jpeg", "public.png", "com.microsoft.bmp" },
+ MimeTypes = new[] { "image/jpeg", "image/png", "image/bmp" }
}
}
+ });
+
+ if (result.Count > 0)
+ {
+ _profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath));
+ _parent.GoBack();
}
}
diff --git a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
index 62b5e1840..debf4b843 100644
--- a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
@@ -12,7 +12,6 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:Class="Ryujinx.Ava.UI.Views.User.UserRecovererView"
- x:CompileBindings="True"
x:DataType="viewModels:UserProfileViewModel"
Focusable="True">
@@ -33,7 +32,7 @@
+ ItemsSource="{Binding LostProfiles}">
@@ -107,8 +106,7 @@
VerticalAlignment="Stretch">
@@ -117,7 +115,7 @@
-
diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
index 9a6ba054e..818a21d69 100644
--- a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
+++ b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
@@ -15,7 +15,6 @@
d:DesignWidth="800"
mc:Ignorable="d"
Focusable="True"
- x:CompileBindings="True"
x:DataType="viewModels:UserProfileViewModel">
@@ -38,7 +37,7 @@
VerticalAlignment="Center"
SelectionChanged="ProfilesList_SelectionChanged"
Background="Transparent"
- Items="{Binding Profiles}">
+ ItemsSource="{Binding Profiles}">
-
@@ -61,8 +60,8 @@
+ PointerEntered="Grid_PointerEntered"
+ PointerExited="Grid_OnPointerExited">
@@ -64,14 +63,14 @@
FontWeight="Bold"
Text="Ryujinx"
TextAlignment="Center"
- Width="100" />
+ Width="110" />
+ Width="110" />
-
\ No newline at end of file
+
diff --git a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml b/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml
index 90d47b8ed..caf7c1f3f 100644
--- a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml
+++ b/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml
@@ -1,4 +1,4 @@
-
-
+
-
+
diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml
index 11e86211e..b9cbcb9cc 100644
--- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml
+++ b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml
@@ -40,7 +40,7 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
LineHeight="18"
- Text="{Binding Heading}"
+ Text="{ReflectionBinding Heading}"
TextAlignment="Center"
TextWrapping="Wrap" />
+ ItemsSource="{ReflectionBinding LoadedCheats}">