mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2024-11-24 02:00:11 +01:00
UI: Remove title bar, put icon next to File button. Added icons to most dropdown menu actions. Title bar content is now displayed when hovering the logo in the title bar.
This commit is contained in:
parent
235083ad75
commit
045f9a39bb
@ -19,6 +19,8 @@ namespace Ryujinx.UI.App.Common
|
||||
{
|
||||
public class ApplicationData
|
||||
{
|
||||
public static Func<string> LocalizedNever = () => "Never";
|
||||
|
||||
public bool Favorite { get; set; }
|
||||
public byte[] Icon { get; set; }
|
||||
public string Name { get; set; } = "Unknown";
|
||||
@ -34,7 +36,7 @@ namespace Ryujinx.UI.App.Common
|
||||
|
||||
public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed);
|
||||
|
||||
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed);
|
||||
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed) ?? LocalizedNever();
|
||||
|
||||
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
using ARMeilleure;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
@ -1645,6 +1646,8 @@ namespace Ryujinx.UI.Common.Configuration
|
||||
}
|
||||
|
||||
Instance = new ConfigurationState();
|
||||
|
||||
Instance.System.EnableLowPowerPtc.Event += (_, evnt) => Optimizations.LowPower = evnt.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +75,7 @@ namespace Ryujinx.UI.Common.Helper
|
||||
{
|
||||
culture ??= CultureInfo.CurrentCulture;
|
||||
|
||||
if (!utcDateTime.HasValue)
|
||||
{
|
||||
// In the Avalonia UI, this is turned into a localized version of "Never" by LocalizedNeverConverter.
|
||||
return "Never";
|
||||
}
|
||||
|
||||
return utcDateTime.Value.ToLocalTime().ToString(culture);
|
||||
return utcDateTime?.ToLocalTime().ToString(culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
26
src/Ryujinx/Common/Icon/IconExtension.cs
Normal file
26
src/Ryujinx/Common/Icon/IconExtension.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Avalonia.Data.Core;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Markup.Xaml.MarkupExtensions;
|
||||
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Common.Icon
|
||||
{
|
||||
internal class IconExtension(string iconString) : MarkupExtension
|
||||
{
|
||||
private ClrPropertyInfo PropertyInfo
|
||||
=> new(
|
||||
"Item",
|
||||
_ => new Projektanker.Icons.Avalonia.Icon { Value = iconString },
|
||||
null,
|
||||
typeof(Projektanker.Icons.Avalonia.Icon)
|
||||
);
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) =>
|
||||
new CompiledBindingExtension(
|
||||
new CompiledBindingPathBuilder()
|
||||
.Property(PropertyInfo, PropertyInfoAccessorFactory.CreateInpcPropertyAccessor)
|
||||
.Build()
|
||||
).ProvideValue(serviceProvider);
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
using ARMeilleure;
|
||||
using Avalonia;
|
||||
using Avalonia.Threading;
|
||||
using DiscordRPC;
|
||||
using Projektanker.Icons.Avalonia;
|
||||
using Projektanker.Icons.Avalonia.FontAwesome;
|
||||
using Projektanker.Icons.Avalonia.MaterialDesign;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common;
|
||||
@ -11,6 +16,7 @@ using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using Ryujinx.UI.App.Common;
|
||||
using Ryujinx.UI.Common;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
@ -51,31 +57,32 @@ namespace Ryujinx.Ava
|
||||
|
||||
LoggerAdapter.Register();
|
||||
|
||||
IconProvider.Current
|
||||
.Register<FontAwesomeIconProvider>()
|
||||
.Register<MaterialDesignIconProvider>();
|
||||
|
||||
return BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
{
|
||||
return AppBuilder.Configure<App>()
|
||||
public static AppBuilder BuildAvaloniaApp() =>
|
||||
AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.With(new X11PlatformOptions
|
||||
{
|
||||
EnableMultiTouch = true,
|
||||
EnableIme = true,
|
||||
EnableInputFocusProxy = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP") == "gamescope",
|
||||
RenderingMode = UseHardwareAcceleration ?
|
||||
new[] { X11RenderingMode.Glx, X11RenderingMode.Software } :
|
||||
new[] { X11RenderingMode.Software },
|
||||
RenderingMode = UseHardwareAcceleration
|
||||
? [ X11RenderingMode.Glx, X11RenderingMode.Software ]
|
||||
: [ X11RenderingMode.Software ],
|
||||
})
|
||||
.With(new Win32PlatformOptions
|
||||
{
|
||||
WinUICompositionBackdropCornerRadius = 8.0f,
|
||||
RenderingMode = UseHardwareAcceleration ?
|
||||
new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software } :
|
||||
new[] { Win32RenderingMode.Software },
|
||||
})
|
||||
.UseSkia();
|
||||
}
|
||||
RenderingMode = UseHardwareAcceleration
|
||||
? [ Win32RenderingMode.AngleEgl, Win32RenderingMode.Software ]
|
||||
: [ Win32RenderingMode.Software ],
|
||||
});
|
||||
|
||||
private static void Initialize(string[] args)
|
||||
{
|
||||
@ -102,6 +109,9 @@ namespace Ryujinx.Ava
|
||||
// Setup base data directory.
|
||||
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
||||
|
||||
// Set the delegate for localizing the word "never" in the UI
|
||||
ApplicationData.LocalizedNever = () => LocaleManager.Instance[LocaleKeys.Never];
|
||||
|
||||
// Initialize the configuration.
|
||||
ConfigurationState.Initialize();
|
||||
|
||||
@ -218,14 +228,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}");
|
||||
|
||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Launch Mode: Custom Path {AppDataManager.BaseDirPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Launch Mode: {AppDataManager.Mode}");
|
||||
}
|
||||
Logger.Notice.Print(LogClass.Application,
|
||||
AppDataManager.Mode == AppDataManager.LaunchMode.Custom
|
||||
? $"Launch Mode: Custom Path {AppDataManager.BaseDirPath}"
|
||||
: $"Launch Mode: {AppDataManager.Mode}");
|
||||
}
|
||||
|
||||
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
|
||||
|
@ -44,7 +44,9 @@
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" />
|
||||
<PackageReference Include="OpenTK.Core" />
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||
@ -69,8 +71,7 @@
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj"
|
||||
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -122,7 +122,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
{
|
||||
try
|
||||
{
|
||||
_parent.ViewModel.AppHost.NpadManager.BlockInputUpdates();
|
||||
MainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates();
|
||||
var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
|
||||
|
||||
if (response.Result == UserResult.Ok)
|
||||
@ -144,7 +144,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
});
|
||||
|
||||
dialogCloseEvent.WaitOne();
|
||||
_parent.ViewModel.AppHost.NpadManager.UnblockInputUpdates();
|
||||
MainWindow.ViewModel.AppHost.NpadManager.UnblockInputUpdates();
|
||||
|
||||
userText = error ? null : inputText;
|
||||
|
||||
@ -154,7 +154,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||
{
|
||||
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
|
||||
_parent.ViewModel.AppHost?.Stop();
|
||||
MainWindow.ViewModel.AppHost?.Stop();
|
||||
}
|
||||
|
||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_hiddenTextBox.Clear();
|
||||
_parent.ViewModel.RendererHostControl.Focus();
|
||||
MainWindow.ViewModel.RendererHostControl.Focus();
|
||||
|
||||
_parent = null;
|
||||
});
|
||||
|
@ -3,24 +3,29 @@
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:icon="clr-namespace:Ryujinx.Ava.Common.Icon"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
x:DataType="viewModels:MainWindowViewModel">
|
||||
<MenuItem
|
||||
<MenuItem
|
||||
Click="RunApplication_Click"
|
||||
Header="{locale:Locale GameListContextMenuRunApplication}" />
|
||||
Header="{locale:Locale GameListContextMenuRunApplication}"
|
||||
Icon="{icon:Icon fa-solid fa-play}"/>
|
||||
<MenuItem
|
||||
Click="ToggleFavorite_Click"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
Icon="{icon:Icon fa-solid fa-star}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<MenuItem
|
||||
Click="CreateApplicationShortcut_Click"
|
||||
Header="{locale:Locale GameListContextMenuCreateShortcut}"
|
||||
<MenuItem
|
||||
Click="CreateApplicationShortcut_Click"
|
||||
Header="{locale:Locale GameListContextMenuCreateShortcut}"
|
||||
IsEnabled="{Binding CreateShortcutEnabled}"
|
||||
ToolTip.Tip="{OnPlatform Default={locale:Locale GameListContextMenuCreateShortcutToolTip}, macOS={locale:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" />
|
||||
Icon="{icon:Icon fa-solid fa-bookmark}"
|
||||
ToolTip.Tip="{OnPlatform Default={locale:Locale GameListContextMenuCreateShortcutToolTip}, macOS={locale:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenUserSaveDirectory_Click"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
Icon="{icon:Icon mdi-folder-account}"
|
||||
IsEnabled="{Binding OpenUserSaveDirectoryEnabled}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
@ -37,45 +42,55 @@
|
||||
<MenuItem
|
||||
Click="OpenTitleUpdateManager_Click"
|
||||
Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
|
||||
Icon="{icon:Icon fa-solid fa-code-compare}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenDownloadableContentManager_Click"
|
||||
Header="{locale:Locale GameListContextMenuManageDlc}"
|
||||
Icon="{icon:Icon fa-solid fa-download}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenCheatManager_Click"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
Icon="{icon:Icon fa-solid fa-code}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenModManager_Click"
|
||||
Header="{locale:Locale GameListContextMenuManageMod}"
|
||||
Icon="{icon:Icon mdi-view-module}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageModToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenModsDirectory_Click"
|
||||
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
|
||||
Icon="{icon:Icon mdi-folder-file}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenSdModsDirectory_Click"
|
||||
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
Icon="{icon:Icon mdi-folder-file}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}" Icon="{icon:Icon mdi-cached}">
|
||||
<MenuItem
|
||||
Click="PurgePtcCache_Click"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
Icon="{icon:Icon mdi-refresh}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Click="PurgeShaderCache_Click"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
Icon="{icon:Icon mdi-delete-alert}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenPtcDirectory_Click"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
Icon="{icon:Icon mdi-folder-arrow-up-down}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenShaderCacheDirectory_Click"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
Icon="{icon:Icon mdi-folder-arrow-up-down}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
|
||||
|
@ -13,6 +13,7 @@ using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.UI.App.Common;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -34,165 +35,132 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public void ToggleFavorite_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
|
||||
|
||||
ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
|
||||
{
|
||||
viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
|
||||
appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
|
||||
});
|
||||
|
||||
ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
|
||||
{
|
||||
appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
|
||||
});
|
||||
|
||||
viewModel.RefreshView();
|
||||
}
|
||||
viewModel.RefreshView();
|
||||
}
|
||||
|
||||
public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel viewModel })
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Account, new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenDeviceSaveDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Device, default);
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Device, default);
|
||||
}
|
||||
|
||||
public void OpenBcatSaveDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Bcat, default);
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Bcat, default);
|
||||
}
|
||||
|
||||
private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
|
||||
{
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
|
||||
var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
|
||||
|
||||
ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name);
|
||||
}
|
||||
ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name);
|
||||
}
|
||||
|
||||
public async void OpenTitleUpdateManager_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await TitleUpdateWindow.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication);
|
||||
}
|
||||
}
|
||||
|
||||
public async void OpenDownloadableContentManager_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await DownloadableContentManagerWindow.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication);
|
||||
}
|
||||
}
|
||||
|
||||
public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await new CheatWindow(
|
||||
viewModel.VirtualFileSystem,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window);
|
||||
}
|
||||
viewModel.SelectedApplication.Path).ShowDialog((Window)viewModel.TopLevel);
|
||||
}
|
||||
|
||||
public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
|
||||
public void OpenSdModsDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
|
||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
|
||||
public async void OpenModManager_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await ModManagerWindow.Show(viewModel.SelectedApplication.Id, viewModel.SelectedApplication.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name)
|
||||
);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1"));
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
List<FileInfo> cacheFiles = new();
|
||||
|
||||
if (mainDir.Exists)
|
||||
{
|
||||
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1"));
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
List<FileInfo> cacheFiles = new();
|
||||
if (backupDir.Exists)
|
||||
{
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
if (mainDir.Exists)
|
||||
if (cacheFiles.Count > 0)
|
||||
{
|
||||
foreach (FileInfo file in cacheFiles)
|
||||
{
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
if (backupDir.Exists)
|
||||
{
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
if (cacheFiles.Count > 0)
|
||||
{
|
||||
foreach (FileInfo file in cacheFiles)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
|
||||
}
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,55 +169,51 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public async void PurgeShaderCache_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name)
|
||||
);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"));
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
List<DirectoryInfo> oldCacheDirectories = new();
|
||||
List<FileInfo> newCacheFiles = new();
|
||||
|
||||
if (shaderCacheDir.Exists)
|
||||
{
|
||||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"));
|
||||
oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*"));
|
||||
newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc"));
|
||||
newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data"));
|
||||
}
|
||||
|
||||
List<DirectoryInfo> oldCacheDirectories = new();
|
||||
List<FileInfo> newCacheFiles = new();
|
||||
|
||||
if (shaderCacheDir.Exists)
|
||||
if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0))
|
||||
{
|
||||
foreach (DirectoryInfo directory in oldCacheDirectories)
|
||||
{
|
||||
oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*"));
|
||||
newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc"));
|
||||
newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data"));
|
||||
try
|
||||
{
|
||||
directory.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, ex));
|
||||
}
|
||||
}
|
||||
|
||||
if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0))
|
||||
foreach (FileInfo file in newCacheFiles)
|
||||
{
|
||||
foreach (DirectoryInfo directory in oldCacheDirectories)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
directory.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, ex));
|
||||
}
|
||||
file.Delete();
|
||||
}
|
||||
|
||||
foreach (FileInfo file in newCacheFiles)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, ex));
|
||||
}
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,30 +222,26 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public void OpenPtcDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu");
|
||||
string mainDir = Path.Combine(ptcDir, "0");
|
||||
string backupDir = Path.Combine(ptcDir, "1");
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
if (!Directory.Exists(ptcDir))
|
||||
{
|
||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu");
|
||||
string mainDir = Path.Combine(ptcDir, "0");
|
||||
string backupDir = Path.Combine(ptcDir, "1");
|
||||
|
||||
if (!Directory.Exists(ptcDir))
|
||||
{
|
||||
Directory.CreateDirectory(ptcDir);
|
||||
Directory.CreateDirectory(mainDir);
|
||||
Directory.CreateDirectory(backupDir);
|
||||
}
|
||||
|
||||
OpenHelper.OpenFolder(ptcDir);
|
||||
Directory.CreateDirectory(ptcDir);
|
||||
Directory.CreateDirectory(mainDir);
|
||||
Directory.CreateDirectory(backupDir);
|
||||
}
|
||||
|
||||
OpenHelper.OpenFolder(ptcDir);
|
||||
}
|
||||
|
||||
public void OpenShaderCacheDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
{
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader");
|
||||
|
||||
@ -296,9 +256,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public async void ExtractApplicationExeFs_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
{
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
@ -310,67 +268,60 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public async void ExtractApplicationRomFs_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Data,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
if (viewModel?.SelectedApplication is { } selectedApp)
|
||||
var result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
var result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
});
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (result.Count == 0)
|
||||
return;
|
||||
|
||||
ApplicationHelper.ExtractSection(
|
||||
result[0].Path.LocalPath,
|
||||
NcaSectionType.Logo,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
ApplicationHelper.ExtractSection(
|
||||
result[0].Path.LocalPath,
|
||||
NcaSectionType.Logo,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
|
||||
var iconFile = await result[0].CreateFileAsync(selectedApp.IdString + ".png");
|
||||
await using var fileStream = await iconFile.OpenWriteAsync();
|
||||
var iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
|
||||
await using var fileStream = await iconFile.OpenWriteAsync();
|
||||
|
||||
fileStream.Write(selectedApp.Icon);
|
||||
}
|
||||
using var bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
|
||||
.Resize(new SKSizeI(512, 512), SKFilterQuality.High);
|
||||
|
||||
using var png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||
|
||||
png.SaveTo(fileStream);
|
||||
}
|
||||
|
||||
public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
ApplicationData selectedApplication = viewModel.SelectedApplication;
|
||||
ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.Name, selectedApplication.IdString, selectedApplication.Icon);
|
||||
}
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
ShortcutHelper.CreateAppShortcut(
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Icon
|
||||
);
|
||||
}
|
||||
|
||||
public async void RunApplication_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
|
||||
|
||||
if (viewModel?.SelectedApplication != null)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
await viewModel.LoadApplication(viewModel.SelectedApplication);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,37 +15,22 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
add => AddHandler(ApplicationOpenedEvent, value);
|
||||
remove => RemoveHandler(ApplicationOpenedEvent, value);
|
||||
}
|
||||
|
||||
public ApplicationGridView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public ApplicationGridView() => InitializeComponent();
|
||||
|
||||
public void GameList_DoubleTapped(object sender, TappedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
if (sender is ListBox { SelectedItem: ApplicationData selected })
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).GridSelectedApplication = listBox.SelectedItem as ApplicationData;
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
if (DataContext is MainWindowViewModel viewModel && sender is ListBox { SelectedItem: ApplicationData selected })
|
||||
viewModel.GridSelectedApplication = selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@
|
||||
Spacing="5">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Id, StringFormat=X16}"
|
||||
Text="{Binding IdString}"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
@ -131,7 +131,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}"
|
||||
Text="{Binding LastPlayedString}"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
|
@ -15,37 +15,22 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
add => AddHandler(ApplicationOpenedEvent, value);
|
||||
remove => RemoveHandler(ApplicationOpenedEvent, value);
|
||||
}
|
||||
|
||||
public ApplicationListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public ApplicationListView() => InitializeComponent();
|
||||
|
||||
public void GameList_DoubleTapped(object sender, TappedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
if (sender is ListBox { SelectedItem: ApplicationData selected })
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).ListSelectedApplication = listBox.SelectedItem as ApplicationData;
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
if (DataContext is MainWindowViewModel viewModel && sender is ListBox { SelectedItem: ApplicationData selected })
|
||||
viewModel.ListSelectedApplication = selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||
|
||||
_mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
||||
MainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
||||
|
||||
_isLoaded = false;
|
||||
|
||||
@ -847,7 +847,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
}
|
||||
}
|
||||
|
||||
_mainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||
MainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||
|
||||
// Atomically replace and signal input change.
|
||||
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
|
||||
@ -879,7 +879,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
||||
|
||||
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
|
||||
MainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
|
||||
|
||||
SelectedGamepad?.Dispose();
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:icon="clr-namespace:Ryujinx.Ava.Common.Icon"
|
||||
mc:Ignorable="d"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
x:DataType="viewModels:MainWindowViewModel"
|
||||
@ -12,6 +13,13 @@
|
||||
<viewModels:MainWindowViewModel />
|
||||
</Design.DataContext>
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<Border Padding="7, 0, 0, 0" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<Image
|
||||
ToolTip.Tip="{Binding Title}"
|
||||
Height="25"
|
||||
Width="25"
|
||||
Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" />
|
||||
</Border>
|
||||
<Menu
|
||||
Name="Menu"
|
||||
Height="35"
|
||||
@ -27,27 +35,32 @@
|
||||
<MenuItem
|
||||
Command="{Binding OpenFile}"
|
||||
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
||||
Icon="{icon:Icon fa-solid fa-file}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenFolder}"
|
||||
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
||||
Icon="{icon:Icon fa-solid fa-folder}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
||||
<MenuItem
|
||||
Command="{Binding LoadDlcFromFolder}"
|
||||
Header="{locale:Locale MenuBarFileLoadDlcFromFolder}"
|
||||
Icon="{icon:Icon fa-solid fa-download}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadDlcFromFolderTooltip}" />
|
||||
<MenuItem
|
||||
Command="{Binding LoadTitleUpdatesFromFolder}"
|
||||
Header="{locale:Locale MenuBarFileLoadTitleUpdatesFromFolder}"
|
||||
Icon="{icon:Icon fa-solid fa-code-compare}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadTitleUpdatesFromFolderTooltip}" />
|
||||
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
|
||||
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}" Icon="{icon:Icon mdi-launch}">
|
||||
<MenuItem
|
||||
Click="OpenMiiApplet"
|
||||
Header="Mii Edit Applet"
|
||||
Icon="{icon:Icon fa-solid fa-person}"
|
||||
ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
@ -63,14 +76,28 @@
|
||||
<MenuItem
|
||||
Click="CloseWindow"
|
||||
Header="{locale:Locale MenuBarFileExit}"
|
||||
Icon="{icon:Icon fa-solid fa-xmark}"
|
||||
ToolTip.Tip="{locale:Locale ExitTooltip}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
||||
<MenuItem
|
||||
Padding="-10,0,0,0"
|
||||
Command="{Binding ToggleFullscreen}"
|
||||
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
||||
InputGesture="F11" />
|
||||
Padding="0"
|
||||
Icon="{icon:Icon fa-solid fa-expand}"
|
||||
InputGesture="F11">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Padding="0"
|
||||
Command="{Binding ToggleStartGamesInFullscreen}"
|
||||
@ -100,7 +127,7 @@
|
||||
Command="{Binding ToggleShowConsole}"
|
||||
Header="{locale:Locale MenuBarOptionsShowConsole}">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox
|
||||
<CheckBox
|
||||
MinWidth="{DynamicResource CheckBoxSize}"
|
||||
MinHeight="{DynamicResource CheckBoxSize}"
|
||||
IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
||||
@ -118,11 +145,24 @@
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<Separator/>
|
||||
<MenuItem
|
||||
Name="ChangeLanguageMenuItem"
|
||||
Padding="-10,0,0,0"
|
||||
Header="{locale:Locale MenuBarOptionsChangeLanguage}" />
|
||||
Padding="0"
|
||||
Header="{locale:Locale MenuBarOptionsChangeLanguage}"
|
||||
Icon="{icon:Icon fa-solid fa-language}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Name="ToggleFileTypesMenuItem"
|
||||
Padding="-10,0,0,0"
|
||||
@ -130,15 +170,41 @@
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenSettings"
|
||||
Padding="-10,0,0,0"
|
||||
Padding="0"
|
||||
Header="{locale:Locale MenuBarOptionsSettings}"
|
||||
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
||||
Icon="{icon:Icon fa-solid fa-gear}"
|
||||
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding ManageProfiles}"
|
||||
Padding="-10,0,0,0"
|
||||
Padding="0"
|
||||
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
||||
Icon="{icon:Icon mdi-account}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
||||
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Name="ActionsMenuItem"
|
||||
@ -148,18 +214,21 @@
|
||||
<MenuItem
|
||||
Click="PauseEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsPauseEmulation}"
|
||||
Icon="{icon:Icon fa-solid fa-pause}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding !IsPaused}"
|
||||
IsVisible="{Binding !IsPaused}" />
|
||||
<MenuItem
|
||||
Click="ResumeEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsResumeEmulation}"
|
||||
Icon="{icon:Icon fa-solid fa-play}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding IsPaused}"
|
||||
IsVisible="{Binding IsPaused}" />
|
||||
<MenuItem
|
||||
Click="StopEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsStopEmulation}"
|
||||
Icon="{icon:Icon fa-solid fa-stop}"
|
||||
InputGesture="Escape"
|
||||
IsEnabled="{Binding IsGameRunning}"
|
||||
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
||||
@ -170,26 +239,30 @@
|
||||
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
||||
Click="OpenAmiiboWindow"
|
||||
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
||||
Icon="{icon:Icon mdi-cube-scan}"
|
||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||
<MenuItem
|
||||
Command="{Binding TakeScreenshot}"
|
||||
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
||||
Icon="{icon:Icon mdi-monitor-screenshot}"
|
||||
InputGesture="{Binding ScreenshotKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Command="{Binding HideUi}"
|
||||
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
||||
Icon="{icon:Icon mdi-eye-off}"
|
||||
InputGesture="{Binding ShowUiKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Click="OpenCheatManagerForCurrentApp"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
Icon="{icon:Icon fa-solid fa-code}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" Icon="{icon:Icon fa-solid fa-download}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" Icon="{icon:Icon mdi-file-cog}" />
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" Icon="{icon:Icon mdi-folder-cog}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click"/>
|
||||
@ -198,8 +271,8 @@
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarView}">
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarViewWindow}">
|
||||
<MenuItem Header="{locale:Locale MenuBarViewWindow720}" Tag="720" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{locale:Locale MenuBarViewWindow1080}" Tag="1080" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{locale:Locale MenuBarViewWindow720}" Tag="720 1280" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{locale:Locale MenuBarViewWindow1080}" Tag="1080 1920" Click="ChangeWindowSize_Click" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
|
||||
@ -208,11 +281,13 @@
|
||||
IsEnabled="{Binding CanUpdate}"
|
||||
Click="CheckForUpdates"
|
||||
Header="{locale:Locale MenuBarHelpCheckForUpdates}"
|
||||
Icon="{icon:Icon mdi-update}"
|
||||
ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenAboutWindow"
|
||||
Header="{locale:Locale MenuBarHelpAbout}"
|
||||
Icon="{icon:Icon fa-solid fa-circle-info}"
|
||||
ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
@ -2,6 +2,7 @@ using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
using Gommon;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
@ -77,11 +78,9 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
|
||||
MenuItem menuItem = new()
|
||||
{
|
||||
Header = languageName,
|
||||
Command = MiniCommand.Create(() =>
|
||||
{
|
||||
MainWindowViewModel.ChangeLanguage(languageCode);
|
||||
}),
|
||||
Padding = new Thickness(10, 0, 0, 0),
|
||||
Header = " " + languageName,
|
||||
Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(languageCode)),
|
||||
};
|
||||
|
||||
menuItems.Add(menuItem);
|
||||
@ -99,23 +98,23 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
Window = window;
|
||||
}
|
||||
|
||||
ViewModel = Window.ViewModel;
|
||||
ViewModel = MainWindow.ViewModel;
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Window.ViewModel.AppHost?.ShowExitPrompt();
|
||||
await MainWindow.ViewModel.AppHost?.ShowExitPrompt().OrCompleted()!;
|
||||
}
|
||||
|
||||
private void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Window.ViewModel.AppHost?.Pause();
|
||||
MainWindow.ViewModel.AppHost?.Pause();
|
||||
}
|
||||
|
||||
private void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Window.ViewModel.AppHost?.Resume();
|
||||
MainWindow.ViewModel.AppHost?.Resume();
|
||||
}
|
||||
|
||||
public async void OpenSettings(object sender, RoutedEventArgs e)
|
||||
@ -149,9 +148,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!ViewModel.IsAmiiboRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewModel.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
{
|
||||
@ -173,17 +170,15 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!ViewModel.IsGameRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
|
||||
|
||||
await new CheatWindow(
|
||||
Window.VirtualFileSystem,
|
||||
ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText,
|
||||
name,
|
||||
Window.ViewModel.SelectedApplication.Path).ShowDialog(Window);
|
||||
MainWindow.ViewModel.SelectedApplication.Path).ShowDialog(Window);
|
||||
|
||||
ViewModel.AppHost.Device.EnableCheats();
|
||||
}
|
||||
@ -191,85 +186,50 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem)
|
||||
{
|
||||
ViewModel.IsAmiiboRequested = Window.ViewModel.AppHost.Device.System.SearchingForAmiibo(out _);
|
||||
}
|
||||
ViewModel.IsAmiiboRequested = MainWindow.ViewModel.AppHost.Device.System.SearchingForAmiibo(out _);
|
||||
}
|
||||
|
||||
private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (FileAssociationHelper.Install())
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]);
|
||||
}
|
||||
}
|
||||
|
||||
private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (FileAssociationHelper.Uninstall())
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ChangeWindowSize_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem item)
|
||||
if (sender is not MenuItem { Tag: string resolution }) return;
|
||||
|
||||
(int height, int width) = resolution.Split(' ')
|
||||
.Into(parts => (int.Parse(parts[0]), int.Parse(parts[1])));
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
int height;
|
||||
int width;
|
||||
ViewModel.WindowState = WindowState.Normal;
|
||||
|
||||
switch (item.Tag)
|
||||
{
|
||||
case "720":
|
||||
height = 720;
|
||||
width = 1280;
|
||||
break;
|
||||
height += (int)Window.StatusBarHeight + (int)Window.MenuBarHeight;
|
||||
|
||||
case "1080":
|
||||
height = 1080;
|
||||
width = 1920;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentNullException($"Invalid Tag for {item}");
|
||||
}
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
ViewModel.WindowState = WindowState.Normal;
|
||||
|
||||
height += (int)Window.StatusBarHeight + (int)Window.MenuBarHeight;
|
||||
|
||||
Window.Arrange(new Rect(Window.Position.X, Window.Position.Y, width, height));
|
||||
});
|
||||
}
|
||||
Window.Arrange(new Rect(Window.Position.X, Window.Position.Y, width, height));
|
||||
});
|
||||
}
|
||||
|
||||
public async void CheckForUpdates(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
{
|
||||
await Updater.BeginParse(Window, true);
|
||||
}
|
||||
}
|
||||
|
||||
public async void OpenAboutWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await AboutWindow.Show();
|
||||
}
|
||||
public async void OpenAboutWindow(object sender, RoutedEventArgs e) => await AboutWindow.Show();
|
||||
|
||||
public void CloseWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Window.Close();
|
||||
}
|
||||
public void CloseWindow(object sender, RoutedEventArgs e) => Window.Close();
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
Window = window;
|
||||
}
|
||||
|
||||
DataContext = Window.ViewModel;
|
||||
DataContext = MainWindow.ViewModel;
|
||||
}
|
||||
|
||||
private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
Window.ViewModel.AppHost.ToggleVSync();
|
||||
MainWindow.ViewModel.AppHost.ToggleVSync();
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {Window.ViewModel.AppHost.Device.EnableDeviceVsync}");
|
||||
Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {MainWindow.ViewModel.AppHost.Device.EnableDeviceVsync}");
|
||||
}
|
||||
|
||||
private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||
@ -57,9 +57,9 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
private void VolumeStatus_OnPointerWheelChanged(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
// Change the volume by 5% at a time
|
||||
float newValue = Window.ViewModel.Volume + (float)e.Delta.Y * 0.05f;
|
||||
float newValue = MainWindow.ViewModel.Volume + (float)e.Delta.Y * 0.05f;
|
||||
|
||||
Window.ViewModel.Volume = newValue switch
|
||||
MainWindow.ViewModel.Volume = newValue switch
|
||||
{
|
||||
< 0 => 0,
|
||||
> 1 => 1,
|
||||
|
@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
@ -22,9 +22,9 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
||||
if (VisualRoot is MainWindow window)
|
||||
if (VisualRoot is MainWindow)
|
||||
{
|
||||
ViewModel = window.ViewModel;
|
||||
ViewModel = MainWindow.ViewModel;
|
||||
}
|
||||
|
||||
DataContext = ViewModel;
|
||||
@ -32,18 +32,14 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
|
||||
public void Sort_Checked(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is RadioButton button)
|
||||
{
|
||||
ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag.ToString()));
|
||||
}
|
||||
if (sender is RadioButton { Tag: string sortStrategy })
|
||||
ViewModel.Sort(Enum.Parse<ApplicationSort>(sortStrategy));
|
||||
}
|
||||
|
||||
public void Order_Checked(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is RadioButton button)
|
||||
{
|
||||
ViewModel.Sort(button.Tag.ToString() != "Descending");
|
||||
}
|
||||
if (sender is RadioButton { Tag: string sortOrder })
|
||||
ViewModel.Sort(sortOrder is not "Descending");
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
|
@ -6,6 +6,7 @@ using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
using DynamicData;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Windowing;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Ava.Common;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
@ -36,7 +37,9 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public partial class MainWindow : StyleableWindow
|
||||
{
|
||||
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
|
||||
internal static MainWindowViewModel ViewModel { get; private set; }
|
||||
|
||||
internal readonly AvaHostUIHandler UiHandler;
|
||||
|
||||
private bool _isLoading;
|
||||
private bool _applicationsLoadedOnce;
|
||||
@ -46,7 +49,6 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
private static string _launchPath;
|
||||
private static string _launchApplicationId;
|
||||
private static bool _startFullscreen;
|
||||
internal readonly AvaHostUIHandler UiHandler;
|
||||
private IDisposable _appLibraryAppsSubscription;
|
||||
|
||||
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
||||
@ -57,7 +59,6 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
public InputManager InputManager { get; private set; }
|
||||
|
||||
internal MainWindowViewModel ViewModel { get; private set; }
|
||||
public SettingsWindow SettingsWindow { get; set; }
|
||||
|
||||
public static bool ShowKeyErrorOnLoad { get; set; }
|
||||
@ -68,11 +69,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
ViewModel = new MainWindowViewModel();
|
||||
|
||||
MainWindowViewModel = ViewModel;
|
||||
|
||||
DataContext = ViewModel;
|
||||
DataContext = ViewModel = new MainWindowViewModel();
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
@ -81,6 +78,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
ViewModel.Title = App.FormatTitle();
|
||||
|
||||
TitleBar.ExtendsContentIntoTitleBar = true;
|
||||
TitleBar.TitleBarHitTestType = TitleBarHitTestType.Complex;
|
||||
|
||||
|
||||
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
||||
StatusBarHeight = StatusBarView.StatusBar.MinHeight;
|
||||
MenuBarHeight = MenuBar.MinHeight;
|
||||
@ -105,9 +106,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
private void OnPlatformColorValuesChanged(object sender, PlatformColorValues e)
|
||||
{
|
||||
if (Application.Current is App app)
|
||||
{
|
||||
app.ApplyConfiguredTheme();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
|
@ -3,6 +3,7 @@ using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using FluentAvalonia.UI.Windowing;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using System.IO;
|
||||
@ -10,21 +11,13 @@ using System.Reflection;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public class StyleableWindow : Window
|
||||
public class StyleableWindow : AppWindow
|
||||
{
|
||||
public Bitmap IconImage { get; set; }
|
||||
|
||||
public StyleableWindow()
|
||||
{
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
TransparencyLevelHint = [WindowTransparencyLevel.None];
|
||||
|
||||
using Stream stream = Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx.png")!;
|
||||
|
||||
Icon = new WindowIcon(stream);
|
||||
stream.Position = 0;
|
||||
IconImage = new Bitmap(stream);
|
||||
|
||||
LocaleManager.Instance.LocaleChanged += LocaleChanged;
|
||||
LocaleChanged();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user