misc: chore: Use explicit types in the Avalonia project

This commit is contained in:
Evan Husted 2025-01-25 14:00:23 -06:00
parent 3b5f6170d1
commit be3bd0bcb5
69 changed files with 367 additions and 348 deletions

View File

@ -238,10 +238,10 @@ namespace Ryujinx.Ava
_lastCursorMoveTime = Stopwatch.GetTimestamp(); _lastCursorMoveTime = Stopwatch.GetTimestamp();
} }
var point = e.GetCurrentPoint(window).Position; Point point = e.GetCurrentPoint(window).Position;
var bounds = RendererHost.EmbeddedWindow.Bounds; Rect bounds = RendererHost.EmbeddedWindow.Bounds;
var windowYOffset = bounds.Y + window.MenuBarHeight; double windowYOffset = bounds.Y + window.MenuBarHeight;
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
if (!_viewModel.ShowMenuAndStatusBar) if (!_viewModel.ShowMenuAndStatusBar)
{ {
@ -265,10 +265,10 @@ namespace Ryujinx.Ava
if (sender is MainWindow window) if (sender is MainWindow window)
{ {
var point = e.GetCurrentPoint(window).Position; Point point = e.GetCurrentPoint(window).Position;
var bounds = RendererHost.EmbeddedWindow.Bounds; Rect bounds = RendererHost.EmbeddedWindow.Bounds;
var windowYOffset = bounds.Y + window.MenuBarHeight; double windowYOffset = bounds.Y + window.MenuBarHeight;
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
if (!_viewModel.ShowMenuAndStatusBar) if (!_viewModel.ShowMenuAndStatusBar)
{ {
@ -435,7 +435,7 @@ namespace Ryujinx.Ava
return; return;
} }
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888; SKColorType colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
using SKBitmap bitmap = new(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul)); using SKBitmap bitmap = new(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length); Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
@ -448,7 +448,7 @@ namespace Ryujinx.Ava
float scaleX = e.FlipX ? -1 : 1; float scaleX = e.FlipX ? -1 : 1;
float scaleY = e.FlipY ? -1 : 1; float scaleY = e.FlipY ? -1 : 1;
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f); SKMatrix matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
canvas.SetMatrix(matrix); canvas.SetMatrix(matrix);
canvas.DrawBitmap(bitmap, SKPoint.Empty); canvas.DrawBitmap(bitmap, SKPoint.Empty);
@ -467,8 +467,8 @@ namespace Ryujinx.Ava
private static void SaveBitmapAsPng(SKBitmap bitmap, string path) private static void SaveBitmapAsPng(SKBitmap bitmap, string path)
{ {
using var data = bitmap.Encode(SKEncodedImageFormat.Png, 100); using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
using var stream = File.OpenWrite(path); using FileStream stream = File.OpenWrite(path);
data.SaveTo(stream); data.SaveTo(stream);
} }
@ -923,7 +923,7 @@ namespace Ryujinx.Ava
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
var isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); bool isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (isGALThreaded) if (isGALThreaded)
{ {
renderer = new ThreadedRenderer(renderer); renderer = new ThreadedRenderer(renderer);
@ -932,7 +932,7 @@ namespace Ryujinx.Ava
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}"); Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
// Initialize Configuration. // Initialize Configuration.
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value; MemoryConfiguration memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
Device = new Switch(new HLEConfiguration( Device = new Switch(new HLEConfiguration(
VirtualFileSystem, VirtualFileSystem,
@ -970,7 +970,7 @@ namespace Ryujinx.Ava
private static IHardwareDeviceDriver InitializeAudio() private static IHardwareDeviceDriver InitializeAudio()
{ {
var availableBackends = new List<AudioBackend> List<AudioBackend> availableBackends = new List<AudioBackend>
{ {
AudioBackend.SDL2, AudioBackend.SDL2,
AudioBackend.SoundIo, AudioBackend.SoundIo,

View File

@ -144,7 +144,7 @@ namespace Ryujinx.Ava.Common
public static void ExtractSection(string destination, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0) public static void ExtractSection(string destination, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
{ {
var cancellationToken = new CancellationTokenSource(); CancellationTokenSource cancellationToken = new CancellationTokenSource();
UpdateWaitWindow waitingDialog = new( UpdateWaitWindow waitingDialog = new(
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
@ -171,14 +171,14 @@ namespace Ryujinx.Ava.Common
} }
else else
{ {
var pfsTemp = new PartitionFileSystem(); PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp; pfs = pfsTemp;
} }
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{ {
using var ncaFile = new UniqueRef<IFile>(); using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -244,8 +244,8 @@ namespace Ryujinx.Ava.Common
string source = DateTime.Now.ToFileTime().ToString()[10..]; string source = DateTime.Now.ToFileTime().ToString()[10..];
string output = DateTime.Now.ToFileTime().ToString()[10..]; string output = DateTime.Now.ToFileTime().ToString()[10..];
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem); using UniqueRef<IFileSystem> uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination)); using UniqueRef<IFileSystem> uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref); fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref); fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
@ -299,7 +299,7 @@ namespace Ryujinx.Ava.Common
public static void ExtractAoc(string destination, string updateFilePath, string updateName) public static void ExtractAoc(string destination, string updateFilePath, string updateName)
{ {
var cancellationToken = new CancellationTokenSource(); CancellationTokenSource cancellationToken = new CancellationTokenSource();
UpdateWaitWindow waitingDialog = new( UpdateWaitWindow waitingDialog = new(
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
@ -317,13 +317,13 @@ namespace Ryujinx.Ava.Common
string extension = Path.GetExtension(updateFilePath).ToLower(); string extension = Path.GetExtension(updateFilePath).ToLower();
if (extension is ".nsp") if (extension is ".nsp")
{ {
var pfsTemp = new PartitionFileSystem(); PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
IFileSystem pfs = pfsTemp; IFileSystem pfs = pfsTemp;
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{ {
using var ncaFile = new UniqueRef<IFile>(); using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -364,8 +364,8 @@ namespace Ryujinx.Ava.Common
string source = DateTime.Now.ToFileTime().ToString()[10..]; string source = DateTime.Now.ToFileTime().ToString()[10..];
string output = DateTime.Now.ToFileTime().ToString()[10..]; string output = DateTime.Now.ToFileTime().ToString()[10..];
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem); using UniqueRef<IFileSystem> uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination)); using UniqueRef<IFileSystem> uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref); fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref); fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);

View File

@ -32,7 +32,7 @@ namespace Ryujinx.Ava.Common.Locale
private void Load() private void Load()
{ {
var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ? string localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_'); ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_');
LoadLanguage(localeLanguageCode); LoadLanguage(localeLanguageCode);
@ -54,7 +54,7 @@ namespace Ryujinx.Ava.Common.Locale
if (_localeStrings.TryGetValue(key, out string value)) if (_localeStrings.TryGetValue(key, out string value))
{ {
// Check if the localized string needs to be formatted. // Check if the localized string needs to be formatted.
if (_dynamicValues.TryGetValue(key, out var dynamicValue)) if (_dynamicValues.TryGetValue(key, out object[] dynamicValue))
try try
{ {
return string.Format(value, dynamicValue); return string.Format(value, dynamicValue);
@ -99,7 +99,7 @@ namespace Ryujinx.Ava.Common.Locale
public void LoadLanguage(string languageCode) public void LoadLanguage(string languageCode)
{ {
var locale = LoadJsonLanguage(languageCode); Dictionary<LocaleKeys, string> locale = LoadJsonLanguage(languageCode);
if (locale == null) if (locale == null)
{ {
@ -125,7 +125,7 @@ namespace Ryujinx.Ava.Common.Locale
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode) private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode)
{ {
var localeStrings = new Dictionary<LocaleKeys, string>(); Dictionary<LocaleKeys, string> localeStrings = new Dictionary<LocaleKeys, string>();
_localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json") _localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json")
.Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson)); .Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson));
@ -142,10 +142,10 @@ namespace Ryujinx.Ava.Common.Locale
throw new Exception($"Locale key {{{locale.ID}}} has too many languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!"); throw new Exception($"Locale key {{{locale.ID}}} has too many languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!");
} }
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey)) if (!Enum.TryParse<LocaleKeys>(locale.ID, out LocaleKeys localeKey))
continue; continue;
var str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val) string str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
? val ? val
: locale.Translations[DefaultLanguageCode]; : locale.Translations[DefaultLanguageCode];

View File

@ -16,7 +16,7 @@ namespace Ryujinx.Ava.Common.Models
{ {
public static XCITrimmerFileModel FromApplicationData(ApplicationData applicationData, XCIFileTrimmerLog logger) public static XCITrimmerFileModel FromApplicationData(ApplicationData applicationData, XCIFileTrimmerLog logger)
{ {
var trimmer = new XCIFileTrimmer(applicationData.Path, logger); XCIFileTrimmer trimmer = new XCIFileTrimmer(applicationData.Path, logger);
return new XCITrimmerFileModel( return new XCITrimmerFileModel(
applicationData.Name, applicationData.Name,

View File

@ -291,9 +291,9 @@ namespace Ryujinx.Headless
if (!string.IsNullOrEmpty(options.PreferredGPUVendor)) if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{ {
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant(); string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api); DeviceInfo[] devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices) foreach (DeviceInfo device in devices)
{ {
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor) if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{ {

View File

@ -149,7 +149,7 @@ namespace Ryujinx.Headless
AppDataManager.Initialize(option.BaseDataDir); AppDataManager.Initialize(option.BaseDataDir);
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile)) if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out UserProfile profile))
option.UserProfile = profile.Name; option.UserProfile = profile.Name;
// Check if keys exists. // Check if keys exists.

View File

@ -1,4 +1,5 @@
using Humanizer; using Humanizer;
using LibHac.Ns;
using Ryujinx.Ava; using Ryujinx.Ava;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Common; using Ryujinx.Common;
@ -11,6 +12,7 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.HLE.UI; using Ryujinx.HLE.UI;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
@ -165,8 +167,8 @@ namespace Ryujinx.Headless
private void InitializeWindow() private void InitializeWindow()
{ {
var activeProcess = Device.Processes.ActiveApplication; ProcessResult activeProcess = Device.Processes.ActiveApplication;
var nacp = activeProcess.ApplicationControlProperties; ApplicationControlProperty nacp = activeProcess.ApplicationControlProperties;
int desiredLanguage = (int)Device.System.State.DesiredTitleLanguage; int desiredLanguage = (int)Device.System.State.DesiredTitleLanguage;
string titleNameSection = string.IsNullOrWhiteSpace(nacp.Title[desiredLanguage].NameString.ToString()) ? string.Empty : $" - {nacp.Title[desiredLanguage].NameString.ToString()}"; string titleNameSection = string.IsNullOrWhiteSpace(nacp.Title[desiredLanguage].NameString.ToString()) ? string.Empty : $" - {nacp.Title[desiredLanguage].NameString.ToString()}";

View File

@ -91,7 +91,7 @@ namespace Ryujinx.Ava.Input
return false; return false;
} }
AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out var nativeKey); AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out AvaKey nativeKey);
return _pressedKeys.Contains(nativeKey); return _pressedKeys.Contains(nativeKey);
} }

View File

@ -150,14 +150,14 @@ namespace Ryujinx.Ava.Input
static AvaloniaKeyboardMappingHelper() static AvaloniaKeyboardMappingHelper()
{ {
var inputKeys = Enum.GetValues<Key>(); Key[] inputKeys = Enum.GetValues<Key>();
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array. // NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
_avaKeyMapping = new Dictionary<AvaKey, Key>(); _avaKeyMapping = new Dictionary<AvaKey, Key>();
foreach (var key in inputKeys) foreach (Key key in inputKeys)
{ {
if (TryGetAvaKey(key, out var index)) if (TryGetAvaKey(key, out AvaKey index))
{ {
_avaKeyMapping[index] = key; _avaKeyMapping[index] = key;
} }

View File

@ -262,7 +262,7 @@ namespace Ryujinx.Ava
exceptions.Add(initialException); exceptions.Add(initialException);
} }
foreach (var e in exceptions) foreach (Exception e in exceptions)
{ {
string message = $"Unhandled exception caught: {e}"; string message = $"Unhandled exception caught: {e}";
// ReSharper disable once ConstantConditionalAccessQualifier // ReSharper disable once ConstantConditionalAccessQualifier

View File

@ -79,7 +79,7 @@ namespace Ryujinx.Ava
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
var result = await ContentDialogHelper.CreateConfirmationDialog( UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage], LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage],
LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage], LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Applet
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>
{ {
var response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args); UserResult response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args);
if (response == UserResult.Ok) if (response == UserResult.Ok)
{ {
okPressed = true; okPressed = true;

View File

@ -65,7 +65,7 @@ namespace Ryujinx.Ava.UI.Applet
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e) private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
{ {
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key); HidKey key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true)) if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
{ {
@ -85,7 +85,7 @@ namespace Ryujinx.Ava.UI.Applet
private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e) private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e)
{ {
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key); HidKey key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true)) if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
{ {

View File

@ -60,11 +60,11 @@ namespace Ryujinx.Ava.UI.Applet
ObservableCollection<BaseModel> newProfiles = []; ObservableCollection<BaseModel> newProfiles = [];
foreach (var item in ViewModel.Profiles) foreach (BaseModel item in ViewModel.Profiles)
{ {
if (item is UserProfile originalItem) if (item is UserProfile originalItem)
{ {
var profile = new UserProfileSft(originalItem.UserId, originalItem.Name, originalItem.Image); UserProfileSft profile = new UserProfileSft(originalItem.UserId, originalItem.Name, originalItem.Image);
if (profile.UserId == ViewModel.SelectedUserId) if (profile.UserId == ViewModel.SelectedUserId)
{ {

View File

@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.Controls
private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId) private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
{ {
var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default); SaveDataFilter 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);
} }
@ -305,7 +305,7 @@ namespace Ryujinx.Ava.UI.Controls
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
return; return;
var result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle], Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
AllowMultiple = false, AllowMultiple = false,
@ -320,13 +320,13 @@ namespace Ryujinx.Ava.UI.Controls
viewModel.SelectedApplication.Path, viewModel.SelectedApplication.Path,
viewModel.SelectedApplication.Name); viewModel.SelectedApplication.Name);
var iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png"); IStorageFile iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
await using var fileStream = await iconFile.OpenWriteAsync(); await using Stream fileStream = await iconFile.OpenWriteAsync();
using var bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon) using SKBitmap bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
.Resize(new SKSizeI(512, 512), SKFilterQuality.High); .Resize(new SKSizeI(512, 512), SKFilterQuality.High);
using var png = bitmap.Encode(SKEncodedImageFormat.Png, 100); using SKData png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
png.SaveTo(fileStream); png.SaveTo(fileStream);
} }
@ -350,7 +350,7 @@ namespace Ryujinx.Ava.UI.Controls
public async void TrimXCI_Click(object sender, RoutedEventArgs args) public async void TrimXCI_Click(object sender, RoutedEventArgs args)
{ {
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; MainWindowViewModel viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
if (viewModel?.SelectedApplication != null) if (viewModel?.SelectedApplication != null)
{ {

View File

@ -1,6 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Notifications; using Avalonia.Controls.Notifications;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
@ -38,10 +39,10 @@ namespace Ryujinx.Ava.UI.Controls
if (sender is not Button { Content: TextBlock idText }) if (sender is not Button { Content: TextBlock idText })
return; return;
if (!RyujinxApp.IsClipboardAvailable(out var clipboard)) if (!RyujinxApp.IsClipboardAvailable(out IClipboard clipboard))
return; return;
var appData = mwvm.Applications.FirstOrDefault(it => it.IdString == idText.Text); ApplicationData appData = mwvm.Applications.FirstOrDefault(it => it.IdString == idText.Text);
if (appData is null) if (appData is null)
return; return;

View File

@ -106,9 +106,9 @@ namespace Ryujinx.Ava.UI.Controls
.OrderBy(x => x.Name) .OrderBy(x => x.Name)
.ForEach(profile => ViewModel.Profiles.Add(new UserProfile(profile, this))); .ForEach(profile => ViewModel.Profiles.Add(new UserProfile(profile, this)));
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default); SaveDataFilter saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>(); using UniqueRef<SaveDataIterator> saveDataIterator = new UniqueRef<SaveDataIterator>();
HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
@ -127,8 +127,8 @@ namespace Ryujinx.Ava.UI.Controls
for (int i = 0; i < readCount; i++) for (int i = 0; i < readCount; i++)
{ {
var save = saveDataInfo[i]; SaveDataInfo save = saveDataInfo[i];
var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High); UserId id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null) if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
{ {
lostAccounts.Add(id); lostAccounts.Add(id);
@ -136,7 +136,7 @@ namespace Ryujinx.Ava.UI.Controls
} }
} }
foreach (var account in lostAccounts) foreach (UserId account in lostAccounts)
{ {
ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, string.Empty, null), this)); ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, string.Empty, null), this));
} }
@ -146,12 +146,12 @@ namespace Ryujinx.Ava.UI.Controls
public async void DeleteUser(UserProfile userProfile) public async void DeleteUser(UserProfile userProfile)
{ {
var lastUserId = AccountManager.LastOpenedUser.UserId; UserId lastUserId = AccountManager.LastOpenedUser.UserId;
if (userProfile.UserId == lastUserId) if (userProfile.UserId == lastUserId)
{ {
// If we are deleting the currently open profile, then we must open something else before deleting. // If we are deleting the currently open profile, then we must open something else before deleting.
var profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId); UserProfile profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId);
if (profile == null) if (profile == null)
{ {
@ -165,7 +165,7 @@ namespace Ryujinx.Ava.UI.Controls
AccountManager.OpenUser(profile.UserId); AccountManager.OpenUser(profile.UserId);
} }
var result = await ContentDialogHelper.CreateConfirmationDialog( UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage], LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@ -21,7 +21,7 @@ namespace Ryujinx.Ava.UI.Helpers
/// </remarks> /// </remarks>
public static bool ReplaceWith<T>(this AvaloniaList<T> list, T item, bool addIfNotFound = true) public static bool ReplaceWith<T>(this AvaloniaList<T> list, T item, bool addIfNotFound = true)
{ {
var index = list.IndexOf(item); int index = list.IndexOf(item);
if (index != -1) if (index != -1)
{ {
@ -45,9 +45,9 @@ namespace Ryujinx.Ava.UI.Helpers
/// <param name="matchingList">The items to use as matching records to search for in the `sourceList', if not found this item will be added instead</params> /// <param name="matchingList">The items to use as matching records to search for in the `sourceList', if not found this item will be added instead</params>
public static void AddOrReplaceMatching<T>(this AvaloniaList<T> list, IList<T> sourceList, IList<T> matchingList) public static void AddOrReplaceMatching<T>(this AvaloniaList<T> list, IList<T> sourceList, IList<T> matchingList)
{ {
foreach (var match in matchingList) foreach (T match in matchingList)
{ {
var index = sourceList.IndexOf(match); int index = sourceList.IndexOf(match);
if (index != -1) if (index != -1)
{ {
list.ReplaceWith(sourceList[index]); list.ReplaceWith(sourceList[index]);

View File

@ -121,7 +121,7 @@ namespace Ryujinx.Ava.UI.Helpers
startedDeferring = true; startedDeferring = true;
var deferral = args.GetDeferral(); Deferral deferral = args.GetDeferral();
sender.PrimaryButtonClick -= DeferClose; sender.PrimaryButtonClick -= DeferClose;

View File

@ -23,7 +23,7 @@ namespace Ryujinx.Ava.UI.Helpers
} }
public string this[string key] => public string this[string key] =>
_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val) _glyphs.TryGetValue(Enum.Parse<Glyph>(key), out string val)
? val ? val
: string.Empty; : string.Empty;

View File

@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Helpers
return null; return null;
} }
var key = isBundled ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel; LocaleKeys key = isBundled ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel;
return LocaleManager.Instance.UpdateAndGetDynamicValue(key, label); return LocaleManager.Instance.UpdateAndGetDynamicValue(key, label);
} }

View File

@ -50,8 +50,8 @@ namespace Ryujinx.Ava.UI.Helpers
private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) private static string Format(AvaLogLevel level, string area, string template, object source, object[] v)
{ {
var result = new StringBuilder(); StringBuilder result = new StringBuilder();
var r = new CharacterReader(template.AsSpan()); CharacterReader r = new CharacterReader(template.AsSpan());
int i = 0; int i = 0;
result.Append('['); result.Append('[');
@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Helpers
while (!r.End) while (!r.End)
{ {
var c = r.Take(); char c = r.Take();
if (c != '{') if (c != '{')
{ {

View File

@ -28,7 +28,7 @@ namespace Ryujinx.Ava.UI.Helpers
Margin = new Thickness(0, 0, 15, 40), Margin = new Thickness(0, 0, 15, 40),
}; };
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>( Lazy<AsyncWorkQueue<Notification>> maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
() => new AsyncWorkQueue<Notification>(notification => () => new AsyncWorkQueue<Notification>(notification =>
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
@ -57,7 +57,7 @@ namespace Ryujinx.Ava.UI.Helpers
public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null) public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null)
{ {
var delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs); TimeSpan delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs);
_notifications.Add(new Notification(title, text, type, delay, onClick, onClose)); _notifications.Add(new Notification(title, text, type, delay, onClick, onClose));
} }

View File

@ -28,7 +28,7 @@ namespace Ryujinx.Ava.UI.Models
} }
set set
{ {
foreach (var cheat in SubNodes) foreach (CheatNode cheat in SubNodes)
{ {
cheat.IsEnabled = value; cheat.IsEnabled = value;
cheat.OnPropertyChanged(); cheat.OnPropertyChanged();

View File

@ -367,7 +367,7 @@ namespace Ryujinx.Ava.UI.Models.Input
public InputConfig GetConfig() public InputConfig GetConfig()
{ {
var config = new StandardKeyboardInputConfig StandardKeyboardInputConfig config = new StandardKeyboardInputConfig
{ {
Id = Id, Id = Id,
Backend = InputBackendType.WindowKeyboard, Backend = InputBackendType.WindowKeyboard,

View File

@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models
TitleId = info.ProgramId; TitleId = info.ProgramId;
UserId = info.UserId; UserId = info.UserId;
var appData = RyujinxApp.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.EqualsIgnoreCase(TitleIdString)); ApplicationData appData = RyujinxApp.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.EqualsIgnoreCase(TitleIdString));
InGameList = appData != null; InGameList = appData != null;
@ -59,13 +59,13 @@ namespace Ryujinx.Ava.UI.Models
} }
else else
{ {
var appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString); ApplicationMetadata appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
Title = appMetadata.Title ?? TitleIdString; Title = appMetadata.Title ?? TitleIdString;
} }
Task.Run(() => Task.Run(() =>
{ {
var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}"); string saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
long totalSize = GetDirectorySize(saveRoot); long totalSize = GetDirectorySize(saveRoot);
@ -74,14 +74,14 @@ namespace Ryujinx.Ava.UI.Models
long size = 0; long size = 0;
if (Directory.Exists(path)) if (Directory.Exists(path))
{ {
var directories = Directory.GetDirectories(path); string[] directories = Directory.GetDirectories(path);
foreach (var directory in directories) foreach (string directory in directories)
{ {
size += GetDirectorySize(directory); size += GetDirectorySize(directory);
} }
var files = Directory.GetFiles(path); string[] files = Directory.GetFiles(path);
foreach (var file in files) foreach (string file in files)
{ {
size += new FileInfo(file).Length; size += new FileInfo(file).Length;
} }

View File

@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Media; using Avalonia.Media;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
@ -87,7 +88,7 @@ namespace Ryujinx.Ava.UI.Models
private void UpdateBackground() private void UpdateBackground()
{ {
var currentApplication = Avalonia.Application.Current; Application currentApplication = Avalonia.Application.Current;
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color); currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
if (color is not null) if (color is not null)

View File

@ -44,13 +44,13 @@ namespace Ryujinx.Ava.UI.Renderer
throw new PlatformNotSupportedException(); throw new PlatformNotSupportedException();
} }
var flags = OpenGLContextFlags.Compat; OpenGLContextFlags flags = OpenGLContextFlags.Compat;
if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None) if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None)
{ {
flags |= OpenGLContextFlags.Debug; flags |= OpenGLContextFlags.Debug;
} }
var graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default; FramebufferFormat graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags); Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags);

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Ava.UI.ViewModels
protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan<string> propertyNames) protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan<string> propertyNames)
{ {
OnPropertyChanged(firstPropertyName); OnPropertyChanged(firstPropertyName);
foreach (var propertyName in propertyNames) foreach (string propertyName in propertyNames)
{ {
OnPropertyChanged(propertyName); OnPropertyChanged(propertyName);
} }

View File

@ -11,6 +11,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -71,7 +72,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadDownloadableContents() private void LoadDownloadableContents()
{ {
var dlcs = _applicationLibrary.DownloadableContents.Items IEnumerable<(DownloadableContentModel Dlc, bool IsEnabled)> dlcs = _applicationLibrary.DownloadableContents.Items
.Where(it => it.Dlc.TitleIdBase == _applicationData.IdBase); .Where(it => it.Dlc.TitleIdBase == _applicationData.IdBase);
bool hasBundledContent = false; bool hasBundledContent = false;
@ -101,11 +102,11 @@ namespace Ryujinx.Ava.UI.ViewModels
.ThenBy(it => it.TitleId) .ThenBy(it => it.TitleId)
.AsObservableChangeSet() .AsObservableChangeSet()
.Filter(Filter) .Filter(Filter)
.Bind(out var view).AsObservableList(); .Bind(out ReadOnlyObservableCollection<DownloadableContentModel> view).AsObservableList();
// NOTE(jpr): this works around a bug where calling _views.Clear also clears SelectedDownloadableContents for // NOTE(jpr): this works around a bug where calling _views.Clear also clears SelectedDownloadableContents for
// some reason. so we save the items here and add them back after // some reason. so we save the items here and add them back after
var items = SelectedDownloadableContents.ToArray(); DownloadableContentModel[] items = SelectedDownloadableContents.ToArray();
Views.Clear(); Views.Clear();
Views.AddRange(view); Views.AddRange(view);
@ -130,7 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add() public async void Add()
{ {
var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
AllowMultiple = true, AllowMultiple = true,
@ -145,10 +146,10 @@ namespace Ryujinx.Ava.UI.ViewModels
}, },
}); });
var totalDlcAdded = 0; int totalDlcAdded = 0;
foreach (var file in result) foreach (IStorageFile file in result)
{ {
if (!AddDownloadableContent(file.Path.LocalPath, out var newDlcAdded)) if (!AddDownloadableContent(file.Path.LocalPath, out int newDlcAdded))
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]); await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]);
} }
@ -171,18 +172,18 @@ namespace Ryujinx.Ava.UI.ViewModels
return false; return false;
} }
if (!_applicationLibrary.TryGetDownloadableContentFromFile(path, out var dlcs) || dlcs.Count == 0) if (!_applicationLibrary.TryGetDownloadableContentFromFile(path, out List<DownloadableContentModel> dlcs) || dlcs.Count == 0)
{ {
return false; return false;
} }
var dlcsForThisGame = dlcs.Where(it => it.TitleIdBase == _applicationData.IdBase).ToList(); List<DownloadableContentModel> dlcsForThisGame = dlcs.Where(it => it.TitleIdBase == _applicationData.IdBase).ToList();
if (dlcsForThisGame.Count == 0) if (dlcsForThisGame.Count == 0)
{ {
return false; return false;
} }
foreach (var dlc in dlcsForThisGame) foreach (DownloadableContentModel dlc in dlcsForThisGame)
{ {
if (!DownloadableContents.Contains(dlc)) if (!DownloadableContents.Contains(dlc))
{ {
@ -246,13 +247,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Save() public void Save()
{ {
var dlcs = DownloadableContents.Select(it => (it, SelectedDownloadableContents.Contains(it))).ToList(); List<(DownloadableContentModel it, bool)> dlcs = DownloadableContents.Select(it => (it, SelectedDownloadableContents.Contains(it))).ToList();
_applicationLibrary.SaveDownloadableContentsForGame(_applicationData, dlcs); _applicationLibrary.SaveDownloadableContentsForGame(_applicationData, dlcs);
} }
private Task ShowNewDlcAddedDialog(int numAdded) private Task ShowNewDlcAddedDialog(int numAdded)
{ {
var msg = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowDlcAddedMessage], numAdded); string msg = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowDlcAddedMessage], numAdded);
return Dispatcher.UIThread.InvokeAsync(async () => return Dispatcher.UIThread.InvokeAsync(async () =>
{ {
await ContentDialogHelper.ShowTextDialog( await ContentDialogHelper.ShowTextDialog(

View File

@ -215,7 +215,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
return; return;
} }
var selected = Devices[_device].Type; DeviceType selected = Devices[_device].Type;
if (selected != DeviceType.None) if (selected != DeviceType.None)
{ {
@ -299,7 +299,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
else else
{ {
var type = DeviceType.None; DeviceType type = DeviceType.None;
if (Config is StandardKeyboardInputConfig) if (Config is StandardKeyboardInputConfig)
{ {
@ -311,7 +311,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
type = DeviceType.Controller; type = DeviceType.Controller;
} }
var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id); (DeviceType Type, string Id, string Name) item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
if (item != default) if (item != default)
{ {
Device = Devices.ToList().FindIndex(x => x.Id == item.Id); Device = Devices.ToList().FindIndex(x => x.Id == item.Id);
@ -331,7 +331,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
string id = GetCurrentGamepadId(); string id = GetCurrentGamepadId();
var type = Devices[Device].Type; DeviceType type = Devices[Device].Type;
if (type == DeviceType.None) if (type == DeviceType.None)
{ {
@ -373,7 +373,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
return string.Empty; return string.Empty;
} }
var device = Devices[Device]; (DeviceType Type, string Id, string Name) device = Devices[Device];
if (device.Type == DeviceType.None) if (device.Type == DeviceType.None)
{ {
@ -485,7 +485,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private string GetProfileBasePath() private string GetProfileBasePath()
{ {
string path = AppDataManager.ProfilesDirPath; string path = AppDataManager.ProfilesDirPath;
var type = Devices[Device == -1 ? 0 : Device].Type; DeviceType type = Devices[Device == -1 ? 0 : Device].Type;
if (type == DeviceType.Keyboard) if (type == DeviceType.Keyboard)
{ {
@ -525,7 +525,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public InputConfig LoadDefaultConfiguration() public InputConfig LoadDefaultConfiguration()
{ {
var activeDevice = Devices.FirstOrDefault(); (DeviceType Type, string Id, string Name) activeDevice = Devices.FirstOrDefault();
if (Devices.Count > 0 && Device < Devices.Count && Device >= 0) if (Devices.Count > 0 && Device < Devices.Count && Device >= 0)
{ {
@ -822,20 +822,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
else else
{ {
var device = Devices[Device]; (DeviceType Type, string Id, string Name) device = Devices[Device];
if (device.Type == DeviceType.Keyboard) if (device.Type == DeviceType.Keyboard)
{ {
var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config; KeyboardInputConfig inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
inputConfig.Id = device.Id; inputConfig.Id = device.Id;
} }
else else
{ {
var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config; GamepadInputConfig inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
inputConfig.Id = device.Id.Split(" ")[0]; inputConfig.Id = device.Id.Split(" ")[0];
} }
var config = !IsController InputConfig config = !IsController
? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig() ? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig()
: (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); : (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
config.ControllerType = Controllers[_controller].Type; config.ControllerType = Controllers[_controller].Type;

View File

@ -1046,9 +1046,9 @@ namespace Ryujinx.Ava.UI.ViewModels
private void PrepareLoadScreen() private void PrepareLoadScreen()
{ {
using MemoryStream stream = new(SelectedIcon); using MemoryStream stream = new(SelectedIcon);
using var gameIconBmp = SKBitmap.Decode(stream); using SKBitmap gameIconBmp = SKBitmap.Decode(stream);
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp); SKColor dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp);
const float ColorMultiple = 0.5f; const float ColorMultiple = 0.5f;
@ -1132,7 +1132,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected) private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected)
{ {
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
AllowMultiple = true, AllowMultiple = true,
@ -1140,10 +1140,10 @@ namespace Ryujinx.Ava.UI.ViewModels
if (result.Count > 0) if (result.Count > 0)
{ {
var dirs = result.Select(it => it.Path.LocalPath).ToList(); List<string> dirs = result.Select(it => it.Path.LocalPath).ToList();
var numAdded = onDirsSelected(dirs, out int numRemoved); int numAdded = onDirsSelected(dirs, out int numRemoved);
var msg = String.Join("\r\n", new string[] { string msg = String.Join("\r\n", new string[] {
string.Format(LocaleManager.Instance[localeMessageRemovedKey], numRemoved), string.Format(LocaleManager.Instance[localeMessageRemovedKey], numRemoved),
string.Format(LocaleManager.Instance[localeMessageAddedKey], numAdded) string.Format(LocaleManager.Instance[localeMessageAddedKey], numAdded)
}); });
@ -1180,17 +1180,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public void LoadConfigurableHotKeys() public void LoadConfigurableHotKeys()
{ {
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out var showUiKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out Avalonia.Input.Key showUiKey))
{ {
ShowUiKey = new KeyGesture(showUiKey); ShowUiKey = new KeyGesture(showUiKey);
} }
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out Avalonia.Input.Key screenshotKey))
{ {
ScreenshotKey = new KeyGesture(screenshotKey); ScreenshotKey = new KeyGesture(screenshotKey);
} }
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out Avalonia.Input.Key pauseKey))
{ {
PauseKey = new KeyGesture(pauseKey); PauseKey = new KeyGesture(pauseKey);
} }
@ -1238,7 +1238,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallFirmwareFromFile() public async Task InstallFirmwareFromFile()
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
@ -1272,7 +1272,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallFirmwareFromFolder() public async Task InstallFirmwareFromFolder()
{ {
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
}); });
@ -1285,7 +1285,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallKeysFromFile() public async Task InstallKeysFromFile()
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
@ -1319,7 +1319,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallKeysFromFolder() public async Task InstallKeysFromFolder()
{ {
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
}); });
@ -1410,7 +1410,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFile() public async Task OpenFile()
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
AllowMultiple = false, AllowMultiple = false,
@ -1501,7 +1501,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFolder() public async Task OpenFolder()
{ {
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
AllowMultiple = false, AllowMultiple = false,
@ -1682,7 +1682,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning) if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
AllowMultiple = false, AllowMultiple = false,
@ -1802,16 +1802,16 @@ namespace Ryujinx.Ava.UI.ViewModels
return; return;
} }
var trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this)); XCIFileTrimmer trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this));
if (trimmer.CanBeTrimmed) if (trimmer.CanBeTrimmed)
{ {
var savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0; double savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
var currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0; double currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
var cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0; double cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings); string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
var result = await ContentDialogHelper.CreateConfirmationDialog( UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.TrimXCIFileDialogPrimaryText], LocaleManager.Instance[LocaleKeys.TrimXCIFileDialogPrimaryText],
secondaryText, secondaryText,
LocaleManager.Instance[LocaleKeys.Continue], LocaleManager.Instance[LocaleKeys.Continue],

View File

@ -12,6 +12,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -77,37 +79,37 @@ namespace Ryujinx.Ava.UI.ViewModels
string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()]; string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()];
foreach (var path in modsBasePaths) foreach (string path in modsBasePaths)
{ {
var inSd = path == ModLoader.GetSdModsBasePath(); bool inSd = path == ModLoader.GetSdModsBasePath();
var modCache = new ModLoader.ModCache(); ModLoader.ModCache modCache = new ModLoader.ModCache();
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId);
foreach (var mod in modCache.RomfsDirs) foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs)
{ {
var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); ModModel modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) if (Mods.All(x => x.Path != mod.Path.Parent.FullName))
{ {
Mods.Add(modModel); Mods.Add(modModel);
} }
} }
foreach (var mod in modCache.RomfsContainers) foreach (ModLoader.Mod<FileInfo> mod in modCache.RomfsContainers)
{ {
Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd));
} }
foreach (var mod in modCache.ExefsDirs) foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.ExefsDirs)
{ {
var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); ModModel modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) if (Mods.All(x => x.Path != mod.Path.Parent.FullName))
{ {
Mods.Add(modModel); Mods.Add(modModel);
} }
} }
foreach (var mod in modCache.ExefsContainers) foreach (ModLoader.Mod<FileInfo> mod in modCache.ExefsContainers)
{ {
Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd));
} }
@ -120,7 +122,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Mods.AsObservableChangeSet() Mods.AsObservableChangeSet()
.Filter(Filter) .Filter(Filter)
.Bind(out var view).AsObservableList(); .Bind(out ReadOnlyObservableCollection<ModModel> view).AsObservableList();
#pragma warning disable MVVMTK0034 // Event to update is fired below #pragma warning disable MVVMTK0034 // Event to update is fired below
_views.Clear(); _views.Clear();
@ -163,10 +165,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Delete(ModModel model, bool removeFromList = true) public void Delete(ModModel model, bool removeFromList = true)
{ {
var isSubdir = true; bool isSubdir = true;
var pathToDelete = model.Path; string pathToDelete = model.Path;
var basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath(); string basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath();
var modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16")); string modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16"));
if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir) if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir)
{ {
@ -175,9 +177,9 @@ namespace Ryujinx.Ava.UI.ViewModels
if (isSubdir) if (isSubdir)
{ {
var parentDir = String.Empty; string parentDir = String.Empty;
foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly)) foreach (string dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly))
{ {
if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path)) if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path))
{ {
@ -229,10 +231,10 @@ namespace Ryujinx.Ava.UI.ViewModels
return; return;
} }
var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); string destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16"));
// TODO: More robust checking for valid mod folders // TODO: More robust checking for valid mod folders
var isDirectoryValid = true; bool isDirectoryValid = true;
if (directories.Length == 0) if (directories.Length == 0)
{ {
@ -248,7 +250,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return; return;
} }
foreach (var dir in directories) foreach (string dir in directories)
{ {
string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir); string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir);
@ -269,9 +271,9 @@ namespace Ryujinx.Ava.UI.ViewModels
Directory.CreateDirectory(dirToCreate); Directory.CreateDirectory(dirToCreate);
} }
var files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories); string[] files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories);
foreach (var file in files) foreach (string file in files)
{ {
File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true);
} }
@ -281,13 +283,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add() public async void Add()
{ {
var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions IReadOnlyList<IStorageFolder> result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle],
AllowMultiple = true, AllowMultiple = true,
}); });
foreach (var folder in result) foreach (IStorageFolder folder in result)
{ {
AddMod(new DirectoryInfo(folder.Path.LocalPath)); AddMod(new DirectoryInfo(folder.Path.LocalPath));
} }

View File

@ -17,6 +17,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan; using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@ -386,7 +387,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
AvailableGpus.Clear(); AvailableGpus.Clear();
var devices = VulkanRenderer.GetPhysicalDevices(); DeviceInfo[] devices = VulkanRenderer.GetPhysicalDevices();
if (devices.Length == 0) if (devices.Length == 0)
{ {
@ -395,7 +396,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
else else
{ {
foreach (var device in devices) foreach (DeviceInfo device in devices)
{ {
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {

View File

@ -41,7 +41,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadUpdates() private void LoadUpdates()
{ {
var updates = ApplicationLibrary.TitleUpdates.Items IEnumerable<(TitleUpdateModel TitleUpdate, bool IsSelected)> updates = ApplicationLibrary.TitleUpdates.Items
.Where(it => it.TitleUpdate.TitleIdBase == ApplicationData.IdBase); .Where(it => it.TitleUpdate.TitleIdBase == ApplicationData.IdBase);
bool hasBundledContent = false; bool hasBundledContent = false;
@ -64,11 +64,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public void SortUpdates() public void SortUpdates()
{ {
var sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version); IOrderedEnumerable<TitleUpdateModel> sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version);
// NOTE(jpr): this works around a bug where calling Views.Clear also clears SelectedUpdate for // NOTE(jpr): this works around a bug where calling Views.Clear also clears SelectedUpdate for
// some reason. so we save the item here and restore it after // some reason. so we save the item here and restore it after
var selected = SelectedUpdate; object selected = SelectedUpdate;
Views.Clear(); Views.Clear();
Views.Add(new TitleUpdateViewModelNoUpdate()); Views.Add(new TitleUpdateViewModelNoUpdate());
@ -96,18 +96,18 @@ namespace Ryujinx.Ava.UI.ViewModels
return false; return false;
} }
if (!ApplicationLibrary.TryGetTitleUpdatesFromFile(path, out var updates)) if (!ApplicationLibrary.TryGetTitleUpdatesFromFile(path, out List<TitleUpdateModel> updates))
{ {
return false; return false;
} }
var updatesForThisGame = updates.Where(it => it.TitleIdBase == ApplicationData.Id).ToList(); List<TitleUpdateModel> updatesForThisGame = updates.Where(it => it.TitleIdBase == ApplicationData.Id).ToList();
if (updatesForThisGame.Count == 0) if (updatesForThisGame.Count == 0)
{ {
return false; return false;
} }
foreach (var update in updatesForThisGame) foreach (TitleUpdateModel update in updatesForThisGame)
{ {
if (!TitleUpdates.Contains(update)) if (!TitleUpdates.Contains(update))
{ {
@ -142,7 +142,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task Add() public async Task Add()
{ {
var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
AllowMultiple = true, AllowMultiple = true,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
@ -156,10 +156,10 @@ namespace Ryujinx.Ava.UI.ViewModels
}, },
}); });
var totalUpdatesAdded = 0; int totalUpdatesAdded = 0;
foreach (var file in result) foreach (IStorageFile file in result)
{ {
if (!AddUpdate(file.Path.LocalPath, out var newUpdatesAdded)) if (!AddUpdate(file.Path.LocalPath, out int newUpdatesAdded))
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]); await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
} }
@ -175,13 +175,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Save() public void Save()
{ {
var updates = TitleUpdates.Select(it => (it, it == SelectedUpdate as TitleUpdateModel)).ToList(); List<(TitleUpdateModel it, bool)> updates = TitleUpdates.Select(it => (it, it == SelectedUpdate as TitleUpdateModel)).ToList();
ApplicationLibrary.SaveTitleUpdatesForGame(ApplicationData, updates); ApplicationLibrary.SaveTitleUpdatesForGame(ApplicationData, updates);
} }
private Task ShowNewUpdatesAddedDialog(int numAdded) private Task ShowNewUpdatesAddedDialog(int numAdded)
{ {
var msg = string.Format(LocaleManager.Instance[LocaleKeys.UpdateWindowUpdateAddedMessage], numAdded); string msg = string.Format(LocaleManager.Instance[LocaleKeys.UpdateWindowUpdateAddedMessage], numAdded);
return Dispatcher.UIThread.InvokeAsync(async () => return Dispatcher.UIThread.InvokeAsync(async () =>
await ContentDialogHelper.ShowTextDialog( await ContentDialogHelper.ShowTextDialog(
LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle], LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle],

View File

@ -68,7 +68,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Images.Clear(); Images.Clear();
foreach (var image in _avatarStore) foreach (KeyValuePair<string, byte[]> image in _avatarStore)
{ {
Images.Add(new ProfileImageModel(image.Key, image.Value)); Images.Add(new ProfileImageModel(image.Key, image.Value));
} }
@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void ChangeImageBackground() private void ChangeImageBackground()
{ {
foreach (var image in Images) foreach (ProfileImageModel image in Images)
{ {
image.BackgroundColor = new SolidColorBrush(BackgroundColor); image.BackgroundColor = new SolidColorBrush(BackgroundColor);
} }
@ -104,7 +104,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy. // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs")) if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
{ {
using var file = new UniqueRef<IFile>(); using UniqueRef<IFile> file = new UniqueRef<IFile>();
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure(); romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();

View File

@ -41,7 +41,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Saves.AsObservableChangeSet() Saves.AsObservableChangeSet()
.Filter(Filter) .Filter(Filter)
.Sort(GetComparer()) .Sort(GetComparer())
.Bind(out var view).AsObservableList(); .Bind(out ReadOnlyObservableCollection<SaveModel> view).AsObservableList();
#pragma warning disable MVVMTK0034 #pragma warning disable MVVMTK0034
_views.Clear(); _views.Clear();

View File

@ -9,6 +9,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using static Ryujinx.Common.Utilities.XCIFileTrimmer; using static Ryujinx.Common.Utilities.XCIFileTrimmer;
@ -54,10 +55,10 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadXCIApplications() private void LoadXCIApplications()
{ {
var apps = ApplicationLibrary.Applications.Items IEnumerable<ApplicationData> apps = ApplicationLibrary.Applications.Items
.Where(app => app.FileExtension == _FileExtXCI); .Where(app => app.FileExtension == _FileExtXCI);
foreach (var xciApp in apps) foreach (ApplicationData xciApp in apps)
AddOrUpdateXCITrimmerFile(CreateXCITrimmerFile(xciApp.Path)); AddOrUpdateXCITrimmerFile(CreateXCITrimmerFile(xciApp.Path));
ApplicationsChanged(); ApplicationsChanged();
@ -67,7 +68,7 @@ namespace Ryujinx.Ava.UI.ViewModels
string path, string path,
OperationOutcome operationOutcome = OperationOutcome.Undetermined) OperationOutcome operationOutcome = OperationOutcome.Undetermined)
{ {
var xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path); ApplicationData xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path);
return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome }; return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome };
} }
@ -156,17 +157,17 @@ namespace Ryujinx.Ava.UI.ViewModels
_processingMode = processingMode; _processingMode = processingMode;
Processing = true; Processing = true;
var cancellationToken = _cancellationTokenSource.Token; CancellationToken cancellationToken = _cancellationTokenSource.Token;
Thread XCIFileTrimThread = new(() => Thread XCIFileTrimThread = new(() =>
{ {
var toProcess = Sort(SelectedXCIFiles List<XCITrimmerFileModel> toProcess = Sort(SelectedXCIFiles
.Where(xci => .Where(xci =>
(processingMode == ProcessingMode.Untrimming && xci.Untrimmable) || (processingMode == ProcessingMode.Untrimming && xci.Untrimmable) ||
(processingMode == ProcessingMode.Trimming && xci.Trimmable) (processingMode == ProcessingMode.Trimming && xci.Trimmable)
)).ToList(); )).ToList();
var viewsSaved = DisplayedXCIFiles.ToList(); List<XCITrimmerFileModel> viewsSaved = DisplayedXCIFiles.ToList();
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
@ -177,19 +178,19 @@ namespace Ryujinx.Ava.UI.ViewModels
try try
{ {
foreach (var xciApp in toProcess) foreach (XCITrimmerFileModel xciApp in toProcess)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
break; break;
var trimmer = new XCIFileTrimmer(xciApp.Path, _logger); XCIFileTrimmer trimmer = new XCIFileTrimmer(xciApp.Path, _logger);
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
ProcessingApplication = xciApp; ProcessingApplication = xciApp;
}); });
var outcome = OperationOutcome.Undetermined; OperationOutcome outcome = OperationOutcome.Undetermined;
try try
{ {
@ -347,7 +348,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Sort(AllXCIFiles) Sort(AllXCIFiles)
.AsObservableChangeSet() .AsObservableChangeSet()
.Filter(Filter) .Filter(Filter)
.Bind(out var view).AsObservableList(); .Bind(out ReadOnlyObservableCollection<XCITrimmerFileModel> view).AsObservableList();
_displayedXCIFiles.Clear(); _displayedXCIFiles.Clear();
_displayedXCIFiles.AddRange(view); _displayedXCIFiles.AddRange(view);

View File

@ -12,6 +12,7 @@ using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using System.Linq; using System.Linq;
using Button = Ryujinx.Input.Button;
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
@ -104,7 +105,7 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed += MouseClick; PointerPressed += MouseClick;
var viewModel = (DataContext as ControllerInputViewModel); ControllerInputViewModel viewModel = (DataContext as ControllerInputViewModel);
IKeyboard keyboard = IKeyboard keyboard =
(IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver
@ -115,7 +116,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
if (e.ButtonValue.HasValue) if (e.ButtonValue.HasValue)
{ {
var buttonValue = e.ButtonValue.Value; Button buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true; viewModel.ParentModel.IsModified = true;
switch (button.Name) switch (button.Name)
@ -223,7 +224,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
IButtonAssigner assigner; IButtonAssigner assigner;
var controllerInputViewModel = DataContext as ControllerInputViewModel; ControllerInputViewModel controllerInputViewModel = DataContext as ControllerInputViewModel;
assigner = new GamepadButtonAssigner( assigner = new GamepadButtonAssigner(
controllerInputViewModel.ParentModel.SelectedGamepad, controllerInputViewModel.ParentModel.SelectedGamepad,

View File

@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
_dialogOpen = true; _dialogOpen = true;
var result = await ContentDialogHelper.CreateDeniableConfirmationDialog( UserResult result = await ContentDialogHelper.CreateDeniableConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage], LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage], LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@ -8,6 +8,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key; using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
@ -71,7 +72,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
if (e.ButtonValue.HasValue) if (e.ButtonValue.HasValue)
{ {
var buttonValue = e.ButtonValue.Value; Button buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true; viewModel.ParentModel.IsModified = true;
switch (button.Name) switch (button.Name)

View File

@ -1,6 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,7 +18,7 @@ namespace Ryujinx.Ava.UI.Views.Input
public MotionInputView(ControllerInputViewModel viewModel) public MotionInputView(ControllerInputViewModel viewModel)
{ {
var config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
_viewModel = new MotionInputViewModel _viewModel = new MotionInputViewModel
{ {
@ -49,7 +50,7 @@ namespace Ryujinx.Ava.UI.Views.Input
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (sender, args) =>
{ {
var config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
config.Slot = content._viewModel.Slot; config.Slot = content._viewModel.Slot;
config.Sensitivity = content._viewModel.Sensitivity; config.Sensitivity = content._viewModel.Sensitivity;
config.GyroDeadzone = content._viewModel.GyroDeadzone; config.GyroDeadzone = content._viewModel.GyroDeadzone;

View File

@ -1,6 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,7 +18,7 @@ namespace Ryujinx.Ava.UI.Views.Input
public RumbleInputView(ControllerInputViewModel viewModel) public RumbleInputView(ControllerInputViewModel viewModel)
{ {
var config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
_viewModel = new RumbleInputViewModel _viewModel = new RumbleInputViewModel
{ {
@ -45,7 +46,7 @@ namespace Ryujinx.Ava.UI.Views.Input
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (sender, args) =>
{ {
var config = viewModel.Config; GamepadInputConfig config = viewModel.Config;
config.StrongRumble = content._viewModel.StrongRumble; config.StrongRumble = content._viewModel.StrongRumble;
config.WeakRumble = content._viewModel.WeakRumble; config.WeakRumble = content._viewModel.WeakRumble;
}; };

View File

@ -4,11 +4,14 @@ using Avalonia.Layout;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Gommon; using Gommon;
using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Compat; using Ryujinx.Ava.Utilities.Compat;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
@ -142,7 +145,7 @@ namespace Ryujinx.Ava.UI.Views.Main
public async Task OpenMiiApplet() public async Task OpenMiiApplet()
{ {
if (!MiiApplet.CanStart(out var appData, out var nacpData)) if (!MiiApplet.CanStart(out ApplicationData appData, out BlitStruct<ApplicationControlProperty> nacpData))
return; return;
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData); await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);

View File

@ -8,6 +8,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key; using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
@ -70,15 +71,15 @@ namespace Ryujinx.Ava.UI.Views.Settings
PointerPressed += MouseClick; PointerPressed += MouseClick;
var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0"); IKeyboard keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0");
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
_currentAssigner.ButtonAssigned += (sender, e) => _currentAssigner.ButtonAssigned += (sender, e) =>
{ {
if (e.ButtonValue.HasValue) if (e.ButtonValue.HasValue)
{ {
var viewModel = (DataContext) as SettingsViewModel; SettingsViewModel viewModel = (DataContext) as SettingsViewModel;
var buttonValue = e.ButtonValue.Value; Button buttonValue = e.ButtonValue.Value;
switch (button.Name) switch (button.Name)
{ {

View File

@ -39,7 +39,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode) switch (arg.NavigationMode)
{ {
case NavigationMode.New: case NavigationMode.New:
var (parent, profile, isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter; (NavigationDialogHost parent, UserProfile profile, bool isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
_isNewUser = isNewUser; _isNewUser = isNewUser;
_profile = profile; _profile = profile;
TempProfile = new TempProfile(_profile); TempProfile = new TempProfile(_profile);

View File

@ -66,11 +66,11 @@ namespace Ryujinx.Ava.UI.Views.User
{ {
if (ViewModel.SelectedImage != null) if (ViewModel.SelectedImage != null)
{ {
using var streamJpg = new MemoryStream(); using MemoryStream streamJpg = new MemoryStream();
using var bitmap = SKBitmap.Decode(ViewModel.SelectedImage); using SKBitmap bitmap = SKBitmap.Decode(ViewModel.SelectedImage);
using var newBitmap = new SKBitmap(bitmap.Width, bitmap.Height); using SKBitmap newBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (var canvas = new SKCanvas(newBitmap)) using (SKCanvas canvas = new SKCanvas(newBitmap))
{ {
canvas.Clear(new SKColor( canvas.Clear(new SKColor(
ViewModel.BackgroundColor.R, ViewModel.BackgroundColor.R,
@ -80,8 +80,8 @@ namespace Ryujinx.Ava.UI.Views.User
canvas.DrawBitmap(bitmap, 0, 0); canvas.DrawBitmap(bitmap, 0, 0);
} }
using (var image = SKImage.FromBitmap(newBitmap)) using (SKImage image = SKImage.FromBitmap(newBitmap))
using (var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100)) using (SKData dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100))
{ {
dataJpeg.SaveTo(streamJpg); dataJpeg.SaveTo(streamJpg);
} }

View File

@ -63,7 +63,7 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e) private async void Import_OnClick(object sender, RoutedEventArgs e)
{ {
var result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions IReadOnlyList<IStorageFile> result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
@ -99,16 +99,16 @@ namespace Ryujinx.Ava.UI.Views.User
private static byte[] ProcessProfileImage(byte[] buffer) private static byte[] ProcessProfileImage(byte[] buffer)
{ {
using var bitmap = SKBitmap.Decode(buffer); using SKBitmap bitmap = SKBitmap.Decode(buffer);
var resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High); SKBitmap resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
using var streamJpg = new MemoryStream(); using MemoryStream streamJpg = new MemoryStream();
if (resizedBitmap != null) if (resizedBitmap != null)
{ {
using var image = SKImage.FromBitmap(resizedBitmap); using SKImage image = SKImage.FromBitmap(resizedBitmap);
using var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100); using SKData dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100);
dataJpeg.SaveTo(streamJpg); dataJpeg.SaveTo(streamJpg);
} }

View File

@ -27,7 +27,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode) switch (arg.NavigationMode)
{ {
case NavigationMode.New: case NavigationMode.New:
var parent = (NavigationDialogHost)arg.Parameter; NavigationDialogHost parent = (NavigationDialogHost)arg.Parameter;
_parent = parent; _parent = parent;

View File

@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode) switch (arg.NavigationMode)
{ {
case NavigationMode.New: case NavigationMode.New:
var (parent, accountManager, client, virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter; (NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter;
_accountManager = accountManager; _accountManager = accountManager;
_horizonClient = client; _horizonClient = client;
_virtualFileSystem = virtualFileSystem; _virtualFileSystem = virtualFileSystem;
@ -67,15 +67,15 @@ namespace Ryujinx.Ava.UI.Views.User
public void LoadSaves() public void LoadSaves()
{ {
ViewModel.Saves.Clear(); ViewModel.Saves.Clear();
var saves = new ObservableCollection<SaveModel>(); ObservableCollection<SaveModel> saves = new ObservableCollection<SaveModel>();
var saveDataFilter = SaveDataFilter.Make( SaveDataFilter saveDataFilter = SaveDataFilter.Make(
programId: default, programId: default,
saveType: SaveDataType.Account, saveType: SaveDataType.Account,
new UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low), new UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low),
saveDataId: default, saveDataId: default,
index: default); index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>(); using UniqueRef<SaveDataIterator> saveDataIterator = new UniqueRef<SaveDataIterator>();
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); _horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
@ -92,10 +92,10 @@ namespace Ryujinx.Ava.UI.Views.User
for (int i = 0; i < readCount; i++) for (int i = 0; i < readCount; i++)
{ {
var save = saveDataInfo[i]; SaveDataInfo save = saveDataInfo[i];
if (save.ProgramId.Value != 0) if (save.ProgramId.Value != 0)
{ {
var saveModel = new SaveModel(save); SaveModel saveModel = new SaveModel(save);
saves.Add(saveModel); saves.Add(saveModel);
} }
} }
@ -130,7 +130,7 @@ namespace Ryujinx.Ava.UI.Views.User
{ {
if (button.DataContext is SaveModel saveModel) if (button.DataContext is SaveModel saveModel)
{ {
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave], UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
LocaleManager.Instance[LocaleKeys.IrreversibleActionNote], LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],
LocaleManager.Instance[LocaleKeys.InputDialogNo], LocaleManager.Instance[LocaleKeys.InputDialogNo],

View File

@ -6,6 +6,7 @@ using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -58,7 +59,7 @@ namespace Ryujinx.Ava.UI.Windows
int cheatAdded = 0; int cheatAdded = 0;
var mods = new ModLoader.ModCache(); ModLoader.ModCache mods = new ModLoader.ModCache();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue); ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue);
@ -67,7 +68,7 @@ namespace Ryujinx.Ava.UI.Windows
CheatNode currentGroup = null; CheatNode currentGroup = null;
foreach (var cheat in mods.Cheats) foreach (ModLoader.Cheat cheat in mods.Cheats)
{ {
if (cheat.Path.FullName != currentCheatFile) if (cheat.Path.FullName != currentCheatFile)
{ {
@ -80,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
LoadedCheats.Add(currentGroup); LoadedCheats.Add(currentGroup);
} }
var model = new CheatNode(cheat.Name, buildId, string.Empty, false, enabled.Contains($"{buildId}-{cheat.Name}")); CheatNode model = new CheatNode(cheat.Name, buildId, string.Empty, false, enabled.Contains($"{buildId}-{cheat.Name}"));
currentGroup?.SubNodes.Add(model); currentGroup?.SubNodes.Add(model);
cheatAdded++; cheatAdded++;
@ -101,7 +102,7 @@ namespace Ryujinx.Ava.UI.Windows
if (NoCheatsFound) if (NoCheatsFound)
return; return;
var enabledCheats = LoadedCheats.SelectMany(it => it.SubNodes) IEnumerable<string> enabledCheats = LoadedCheats.SelectMany(it => it.SubNodes)
.Where(it => it.IsEnabled) .Where(it => it.IsEnabled)
.Select(it => it.BuildIdKey); .Select(it => it.BuildIdKey);

View File

@ -79,7 +79,7 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
foreach (var content in e.AddedItems) foreach (object content in e.AddedItems)
{ {
if (content is DownloadableContentModel model) if (content is DownloadableContentModel model)
{ {
@ -87,7 +87,7 @@ namespace Ryujinx.Ava.UI.Windows
} }
} }
foreach (var content in e.RemovedItems) foreach (object content in e.RemovedItems)
{ {
if (content is DownloadableContentModel model) if (content is DownloadableContentModel model)
{ {

View File

@ -29,7 +29,7 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor GetFilteredColor(SKBitmap image) public static SKColor GetFilteredColor(SKBitmap image)
{ {
var color = GetColor(image); SKColor color = GetColor(image);
// We don't want colors that are too dark. // We don't want colors that are too dark.
@ -49,10 +49,10 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor GetColor(SKBitmap image) public static SKColor GetColor(SKBitmap image)
{ {
var colors = new PaletteColor[TotalColors]; PaletteColor[] colors = new PaletteColor[TotalColors];
var dominantColorBin = new Dictionary<int, int>(); Dictionary<int, int> dominantColorBin = new Dictionary<int, int>();
var buffer = GetBuffer(image); SKColor[] buffer = GetBuffer(image);
int i = 0; int i = 0;
int maxHitCount = 0; int maxHitCount = 0;
@ -70,7 +70,7 @@ namespace Ryujinx.Ava.UI.Windows
byte cg = pixel.Green; byte cg = pixel.Green;
byte cb = pixel.Blue; byte cb = pixel.Blue;
var qck = GetQuantizedColorKey(cr, cg, cb); int qck = GetQuantizedColorKey(cr, cg, cb);
if (dominantColorBin.TryGetValue(qck, out int hitCount)) if (dominantColorBin.TryGetValue(qck, out int hitCount))
{ {
@ -95,7 +95,7 @@ namespace Ryujinx.Ava.UI.Windows
for (i = 0; i < TotalColors; i++) for (i = 0; i < TotalColors; i++)
{ {
var score = GetColorScore(dominantColorBin, maxHitCount, colors[i]); int score = GetColorScore(dominantColorBin, maxHitCount, colors[i]);
if (highScore < score) if (highScore < score)
{ {
@ -109,7 +109,7 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor[] GetBuffer(SKBitmap image) public static SKColor[] GetBuffer(SKBitmap image)
{ {
var pixels = new SKColor[image.Width * image.Height]; SKColor[] pixels = new SKColor[image.Width * image.Height];
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
@ -124,17 +124,17 @@ namespace Ryujinx.Ava.UI.Windows
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color) private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
{ {
var hitCount = dominantColorBin[color.Qck]; int hitCount = dominantColorBin[color.Qck];
var balancedHitCount = BalanceHitCount(hitCount, maxHitCount); int balancedHitCount = BalanceHitCount(hitCount, maxHitCount);
var quantSat = (GetColorSaturation(color) >> SatQuantShift) << SatQuantShift; int quantSat = (GetColorSaturation(color) >> SatQuantShift) << SatQuantShift;
var value = GetColorValue(color); int value = GetColorValue(color);
// If the color is rarely used on the image, // If the color is rarely used on the image,
// then chances are that there's a better candidate, even if the saturation value // then chances are that there's a better candidate, even if the saturation value
// is high. By multiplying the saturation value with a weight, we can lower // is high. By multiplying the saturation value with a weight, we can lower
// it if the color is almost never used (hit count is low). // it if the color is almost never used (hit count is low).
var satWeighted = quantSat; int satWeighted = quantSat;
var satWeight = balancedHitCount << 5; int satWeight = balancedHitCount << 5;
if (satWeight < 0x100) if (satWeight < 0x100)
{ {
satWeighted = (satWeighted * satWeight) >> 8; satWeighted = (satWeighted * satWeight) >> 8;
@ -142,7 +142,7 @@ namespace Ryujinx.Ava.UI.Windows
// Compute score from saturation and dominance of the color. // Compute score from saturation and dominance of the color.
// We prefer more vivid colors over dominant ones, so give more weight to the saturation. // We prefer more vivid colors over dominant ones, so give more weight to the saturation.
var score = ((satWeighted << 1) + balancedHitCount) * value; int score = ((satWeighted << 1) + balancedHitCount) * value;
return score; return score;
} }

View File

@ -8,6 +8,7 @@ using DynamicData;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Windowing; using FluentAvalonia.UI.Windowing;
using Gommon; using Gommon;
using LibHac.Ns;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
@ -171,11 +172,11 @@ namespace Ryujinx.Ava.UI.Windows
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
var ldnGameDataArray = e.LdnData.ToList(); List<LdnGameData> ldnGameDataArray = e.LdnData.ToList();
ViewModel.LdnData.Clear(); ViewModel.LdnData.Clear();
foreach (var application in ViewModel.Applications.Where(it => it.HasControlHolder)) foreach (ApplicationData application in ViewModel.Applications.Where(it => it.HasControlHolder))
{ {
ref var controlHolder = ref application.ControlHolder.Value; ref ApplicationControlProperty controlHolder = ref application.ControlHolder.Value;
ViewModel.LdnData[application.IdString] = ViewModel.LdnData[application.IdString] =
LdnGameData.GetArrayForApp( LdnGameData.GetArrayForApp(
@ -192,7 +193,7 @@ namespace Ryujinx.Ava.UI.Windows
private void UpdateApplicationWithLdnData(ApplicationData application) private void UpdateApplicationWithLdnData(ApplicationData application)
{ {
if (application.HasControlHolder && ViewModel.LdnData.TryGetValue(application.IdString, out var ldnGameDatas)) if (application.HasControlHolder && ViewModel.LdnData.TryGetValue(application.IdString, out LdnGameData.Array ldnGameDatas))
{ {
application.PlayerCount = ldnGameDatas.PlayerCount; application.PlayerCount = ldnGameDatas.PlayerCount;
application.GameCount = ldnGameDatas.GameCount; application.GameCount = ldnGameDatas.GameCount;
@ -690,12 +691,12 @@ namespace Ryujinx.Ava.UI.Windows
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs); ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs);
var autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value; List<string> autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value;
autoloadDirs.ForEach(dir => Logger.Info?.Print(LogClass.Application, $"Auto loading DLC & updates from: {dir}")); autoloadDirs.ForEach(dir => Logger.Info?.Print(LogClass.Application, $"Auto loading DLC & updates from: {dir}"));
if (autoloadDirs.Count > 0) if (autoloadDirs.Count > 0)
{ {
var updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved); int updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved);
var dlcLoaded = ApplicationLibrary.AutoLoadDownloadableContents(autoloadDirs, out int dlcRemoved); int dlcLoaded = ApplicationLibrary.AutoLoadDownloadableContents(autoloadDirs, out int dlcRemoved);
ShowNewContentAddedDialog(dlcLoaded, dlcRemoved, updatesLoaded, updatesRemoved); ShowNewContentAddedDialog(dlcLoaded, dlcRemoved, updatesLoaded, updatesRemoved);
} }

View File

@ -66,7 +66,7 @@ namespace Ryujinx.Ava.UI.Windows
{ {
if (button.DataContext is ModModel model) if (button.DataContext is ModModel model)
{ {
var result = await ContentDialogHelper.CreateConfirmationDialog( UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogWarning], LocaleManager.Instance[LocaleKeys.DialogWarning],
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name), LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name),
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],
@ -83,7 +83,7 @@ namespace Ryujinx.Ava.UI.Windows
private async void DeleteAll(object sender, RoutedEventArgs e) private async void DeleteAll(object sender, RoutedEventArgs e)
{ {
var result = await ContentDialogHelper.CreateConfirmationDialog( UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogWarning], LocaleManager.Instance[LocaleKeys.DialogWarning],
LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage], LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],
@ -109,11 +109,11 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
foreach (var content in e.AddedItems) foreach (object content in e.AddedItems)
{ {
if (content is ModModel model) if (content is ModModel model)
{ {
var index = ViewModel.Mods.IndexOf(model); int index = ViewModel.Mods.IndexOf(model);
if (index != -1) if (index != -1)
{ {
@ -122,11 +122,11 @@ namespace Ryujinx.Ava.UI.Windows
} }
} }
foreach (var content in e.RemovedItems) foreach (object content in e.RemovedItems)
{ {
if (content is ModModel model) if (content is ModModel model)
{ {
var index = ViewModel.Mods.IndexOf(model); int index = ViewModel.Mods.IndexOf(model);
if (index != -1) if (index != -1)
{ {

View File

@ -81,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
foreach (var content in e.AddedItems) foreach (object content in e.AddedItems)
{ {
if (content is XCITrimmerFileModel applicationData) if (content is XCITrimmerFileModel applicationData)
{ {
@ -89,7 +89,7 @@ namespace Ryujinx.Ava.UI.Windows
} }
} }
foreach (var content in e.RemovedItems) foreach (object content in e.RemovedItems)
{ {
if (content is XCITrimmerFileModel applicationData) if (content is XCITrimmerFileModel applicationData)
{ {

View File

@ -71,7 +71,7 @@ namespace Ryujinx.Ava
} }
else if (OperatingSystem.IsLinux()) else if (OperatingSystem.IsLinux())
{ {
var arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64"; string arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64";
_platformExt = $"linux_{arch}.tar.gz"; _platformExt = $"linux_{arch}.tar.gz";
} }
@ -96,10 +96,10 @@ namespace Ryujinx.Ava
using HttpClient jsonClient = ConstructHttpClient(); using HttpClient jsonClient = ConstructHttpClient();
string fetchedJson = await jsonClient.GetStringAsync(LatestReleaseUrl); string fetchedJson = await jsonClient.GetStringAsync(LatestReleaseUrl);
var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse); GithubReleasesJsonResponse fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.TagName; _buildVer = fetched.TagName;
foreach (var asset in fetched.Assets) foreach (GithubReleaseAssetJsonResponse asset in fetched.Assets)
{ {
if (asset.Name.StartsWith("ryujinx") && asset.Name.EndsWith(_platformExt)) if (asset.Name.StartsWith("ryujinx") && asset.Name.EndsWith(_platformExt))
{ {
@ -711,15 +711,15 @@ namespace Ryujinx.Ava
// NOTE: This method should always reflect the latest build layout. // NOTE: This method should always reflect the latest build layout.
private static IEnumerable<string> EnumerateFilesToDelete() private static IEnumerable<string> EnumerateFilesToDelete()
{ {
var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir. IEnumerable<string> files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
// Determine and exclude user files only when the updater is running, not when cleaning old files // Determine and exclude user files only when the updater is running, not when cleaning old files
if (_running && !OperatingSystem.IsMacOS()) if (_running && !OperatingSystem.IsMacOS())
{ {
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list. // Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); IEnumerable<string> oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName); IEnumerable<string> newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename)); IEnumerable<string> userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
// Remove user files from the paths in files. // Remove user files from the paths in files.
files = files.Except(userFiles); files = files.Except(userFiles);

View File

@ -76,14 +76,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
} }
else else
{ {
var pfsTemp = new PartitionFileSystem(); PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp; pfs = pfsTemp;
} }
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{ {
using var ncaFile = new UniqueRef<IFile>(); using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -158,7 +158,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return string.Empty; return string.Empty;
} }
using var nsoFile = new UniqueRef<IFile>(); using UniqueRef<IFile> nsoFile = new UniqueRef<IFile>();
codeFs.OpenFile(ref nsoFile.Ref, $"/{MainExeFs}".ToU8Span(), OpenMode.Read).ThrowIfFailure(); codeFs.OpenFile(ref nsoFile.Ref, $"/{MainExeFs}".ToU8Span(), OpenMode.Read).ThrowIfFailure();

View File

@ -190,7 +190,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception> /// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath) private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath)
{ {
var applications = new List<ApplicationData>(); List<ApplicationData> applications = new List<ApplicationData>();
string extension = Path.GetExtension(filePath).ToLower(); string extension = Path.GetExtension(filePath).ToLower();
foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel)) foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel))
@ -245,7 +245,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
continue; continue;
} }
using var icon = new UniqueRef<IFile>(); using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -313,7 +313,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
case ".nsp": case ".nsp":
case ".pfs0": case ".pfs0":
{ {
var pfs = new PartitionFileSystem(); PartitionFileSystem pfs = new PartitionFileSystem();
pfs.Initialize(file.AsStorage()).ThrowIfFailure(); pfs.Initialize(file.AsStorage()).ThrowIfFailure();
ApplicationData result = GetApplicationFromNsp(pfs, applicationPath); ApplicationData result = GetApplicationFromNsp(pfs, applicationPath);
@ -438,7 +438,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return false; return false;
} }
foreach (var data in applications) foreach (ApplicationData data in applications)
{ {
// Only load metadata for applications with an ID // Only load metadata for applications with an ID
if (data.Id != 0) if (data.Id != 0)
@ -501,7 +501,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{ {
using var ncaFile = new UniqueRef<IFile>(); using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -588,8 +588,8 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData), nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData),
ReadOption.None).ThrowIfFailure(); ReadOption.None).ThrowIfFailure();
var displayVersion = controlData.DisplayVersionString.ToString(); string displayVersion = controlData.DisplayVersionString.ToString();
var update = new TitleUpdateModel(content.ApplicationId, content.Version.Version, TitleUpdateModel update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
displayVersion, filePath); displayVersion, filePath);
titleUpdates.Add(update); titleUpdates.Add(update);
@ -685,11 +685,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return; return;
} }
var fileInfo = new FileInfo(app); FileInfo fileInfo = new FileInfo(app);
try try
{ {
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
applicationPaths.Add(fullPath); applicationPaths.Add(fullPath);
numApplicationsFound++; numApplicationsFound++;
@ -719,7 +719,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{ {
_applications.Edit(it => _applications.Edit(it =>
{ {
foreach (var application in applications) foreach (ApplicationData application in applications)
{ {
it.AddOrUpdate(application); it.AddOrUpdate(application);
LoadDlcForApplication(application); LoadDlcForApplication(application);
@ -840,7 +840,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
try try
{ {
// Remove any downloadable content which can no longer be located on disk // Remove any downloadable content which can no longer be located on disk
var dlcToRemove = _downloadableContents.Items List<(DownloadableContentModel Dlc, bool IsEnabled)> dlcToRemove = _downloadableContents.Items
.Where(dlc => !File.Exists(dlc.Dlc.ContainerPath)) .Where(dlc => !File.Exists(dlc.Dlc.ContainerPath))
.ToList(); .ToList();
dlcToRemove.ForEach(dlc => dlcToRemove.ForEach(dlc =>
@ -882,11 +882,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return newDlcLoaded; return newDlcLoaded;
} }
var fileInfo = new FileInfo(app); FileInfo fileInfo = new FileInfo(app);
try try
{ {
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
dlcPaths.Add(fullPath); dlcPaths.Add(fullPath);
} }
@ -904,7 +904,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
} }
} }
var appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet(); HashSet<ulong> appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
foreach (string dlcPath in dlcPaths) foreach (string dlcPath in dlcPaths)
{ {
@ -913,9 +913,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return newDlcLoaded; return newDlcLoaded;
} }
if (TryGetDownloadableContentFromFile(dlcPath, out var foundDlcs)) if (TryGetDownloadableContentFromFile(dlcPath, out List<DownloadableContentModel> foundDlcs))
{ {
foreach (var dlc in foundDlcs.Where(it => appIdLookup.Contains(it.TitleIdBase))) foreach (DownloadableContentModel dlc in foundDlcs.Where(it => appIdLookup.Contains(it.TitleIdBase)))
{ {
if (!_downloadableContents.Lookup(dlc).HasValue) if (!_downloadableContents.Lookup(dlc).HasValue)
{ {
@ -949,11 +949,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
try try
{ {
var titleIdsToSave = new HashSet<ulong>(); HashSet<ulong> titleIdsToSave = new HashSet<ulong>();
var titleIdsToRefresh = new HashSet<ulong>(); HashSet<ulong> titleIdsToRefresh = new HashSet<ulong>();
// Remove any updates which can no longer be located on disk // Remove any updates which can no longer be located on disk
var updatesToRemove = _titleUpdates.Items List<(TitleUpdateModel TitleUpdate, bool IsSelected)> updatesToRemove = _titleUpdates.Items
.Where(it => !File.Exists(it.TitleUpdate.Path)) .Where(it => !File.Exists(it.TitleUpdate.Path))
.ToList(); .ToList();
@ -998,11 +998,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return numUpdatesLoaded; return numUpdatesLoaded;
} }
var fileInfo = new FileInfo(app); FileInfo fileInfo = new FileInfo(app);
try try
{ {
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName; string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
updatePaths.Add(fullPath); updatePaths.Add(fullPath);
} }
@ -1020,7 +1020,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
} }
} }
var appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet(); HashSet<ulong> appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
foreach (string updatePath in updatePaths) foreach (string updatePath in updatePaths)
{ {
@ -1029,9 +1029,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return numUpdatesLoaded; return numUpdatesLoaded;
} }
if (TryGetTitleUpdatesFromFile(updatePath, out var foundUpdates)) if (TryGetTitleUpdatesFromFile(updatePath, out List<TitleUpdateModel> foundUpdates))
{ {
foreach (var update in foundUpdates.Where(it => appIdLookup.Contains(it.TitleIdBase))) foreach (TitleUpdateModel update in foundUpdates.Where(it => appIdLookup.Contains(it.TitleIdBase)))
{ {
if (!_titleUpdates.Lookup(update).HasValue) if (!_titleUpdates.Lookup(update).HasValue)
{ {
@ -1063,12 +1063,12 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
private bool AddAndAutoSelectUpdate(TitleUpdateModel update) private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
{ {
if (update == null) return false; if (update == null) return false;
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it => DynamicData.Kernel.Optional<(TitleUpdateModel TitleUpdate, bool IsSelected)> currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected); it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
var shouldSelect = !currentlySelected.HasValue || bool shouldSelect = !currentlySelected.HasValue ||
currentlySelected.Value.TitleUpdate.Version < update.Version; currentlySelected.Value.TitleUpdate.Version < update.Version;
_titleUpdates.AddOrUpdate((update, shouldSelect)); _titleUpdates.AddOrUpdate((update, shouldSelect));
@ -1170,7 +1170,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
} }
else else
{ {
var pfsTemp = new PartitionFileSystem(); PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp; pfs = pfsTemp;
@ -1204,7 +1204,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// Read the icon from the ControlFS and store it as a byte array // Read the icon from the ControlFS and store it as a byte array
try try
{ {
using var icon = new UniqueRef<IFile>(); using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, $"/icon_{desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); controlFs.OpenFile(ref icon.Ref, $"/icon_{desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -1222,7 +1222,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
continue; continue;
} }
using var icon = new UniqueRef<IFile>(); using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@ -1330,7 +1330,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (string.IsNullOrWhiteSpace(data.Name)) if (string.IsNullOrWhiteSpace(data.Name))
{ {
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo) foreach (ref readonly ApplicationControlProperty.ApplicationTitle controlTitle in controlData.Title.ItemsRo)
{ {
if (!controlTitle.NameString.IsEmpty()) if (!controlTitle.NameString.IsEmpty())
{ {
@ -1343,7 +1343,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (string.IsNullOrWhiteSpace(data.Developer)) if (string.IsNullOrWhiteSpace(data.Developer))
{ {
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo) foreach (ref readonly ApplicationControlProperty.ApplicationTitle controlTitle in controlData.Title.ItemsRo)
{ {
if (!controlTitle.PublisherString.IsEmpty()) if (!controlTitle.PublisherString.IsEmpty())
{ {
@ -1419,16 +1419,16 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{ {
_downloadableContents.Edit(it => _downloadableContents.Edit(it =>
{ {
var savedDlc = List<(DownloadableContentModel, bool IsEnabled)> savedDlc =
DownloadableContentsHelper.LoadDownloadableContentsJson(_virtualFileSystem, application.IdBase); DownloadableContentsHelper.LoadDownloadableContentsJson(_virtualFileSystem, application.IdBase);
it.AddOrUpdate(savedDlc); it.AddOrUpdate(savedDlc);
if (TryGetDownloadableContentFromFile(application.Path, out var bundledDlc)) if (TryGetDownloadableContentFromFile(application.Path, out List<DownloadableContentModel> bundledDlc))
{ {
var savedDlcLookup = savedDlc.Select(dlc => dlc.Item1).ToHashSet(); HashSet<DownloadableContentModel> savedDlcLookup = savedDlc.Select(dlc => dlc.Item1).ToHashSet();
bool addedNewDlc = false; bool addedNewDlc = false;
foreach (var dlc in bundledDlc) foreach (DownloadableContentModel dlc in bundledDlc)
{ {
if (!savedDlcLookup.Contains(dlc)) if (!savedDlcLookup.Contains(dlc))
{ {
@ -1439,7 +1439,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (addedNewDlc) if (addedNewDlc)
{ {
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList(); List<(DownloadableContentModel Dlc, bool IsEnabled)> gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase, DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase,
gameDlcs); gameDlcs);
} }
@ -1451,22 +1451,22 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// file itself // file itself
private bool LoadTitleUpdatesForApplication(ApplicationData application) private bool LoadTitleUpdatesForApplication(ApplicationData application)
{ {
var modifiedVersion = false; bool modifiedVersion = false;
_titleUpdates.Edit(it => _titleUpdates.Edit(it =>
{ {
var savedUpdates = List<(TitleUpdateModel Update, bool IsSelected)> savedUpdates =
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase); TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
it.AddOrUpdate(savedUpdates); it.AddOrUpdate(savedUpdates);
var selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected); DynamicData.Kernel.Optional<(TitleUpdateModel Update, bool IsSelected)> selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected);
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates)) if (TryGetTitleUpdatesFromFile(application.Path, out List<TitleUpdateModel> bundledUpdates))
{ {
var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet(); HashSet<TitleUpdateModel> savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
bool updatesChanged = false; bool updatesChanged = false;
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version)) foreach (TitleUpdateModel update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
{ {
if (!savedUpdateLookup.Contains(update)) if (!savedUpdateLookup.Contains(update))
{ {
@ -1488,7 +1488,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (updatesChanged) if (updatesChanged)
{ {
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList(); List<(TitleUpdateModel TitleUpdate, bool IsSelected)> gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates); TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates);
} }
} }
@ -1500,14 +1500,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// Save the _currently tracked_ DLC state for the game // Save the _currently tracked_ DLC state for the game
private void SaveDownloadableContentsForGame(ulong titleIdBase) private void SaveDownloadableContentsForGame(ulong titleIdBase)
{ {
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList(); List<(DownloadableContentModel Dlc, bool IsEnabled)> dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs); DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs);
} }
// Save the _currently tracked_ update state for the game // Save the _currently tracked_ update state for the game
private void SaveTitleUpdatesForGame(ulong titleIdBase) private void SaveTitleUpdatesForGame(ulong titleIdBase)
{ {
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList(); List<(TitleUpdateModel TitleUpdate, bool IsSelected)> updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates); TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates);
} }
@ -1515,7 +1515,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// of its state // of its state
private void RefreshApplicationInfo(ulong appIdBase) private void RefreshApplicationInfo(ulong appIdBase)
{ {
var application = _applications.Lookup(appIdBase); DynamicData.Kernel.Optional<ApplicationData> application = _applications.Lookup(appIdBase);
if (!application.HasValue) if (!application.HasValue)
return; return;
@ -1523,7 +1523,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (!TryGetApplicationsFromFile(application.Value.Path, out List<ApplicationData> newApplications)) if (!TryGetApplicationsFromFile(application.Value.Path, out List<ApplicationData> newApplications))
return; return;
var newApplication = newApplications.First(it => it.IdBase == appIdBase); ApplicationData newApplication = newApplications.First(it => it.IdBase == appIdBase);
_applications.AddOrUpdate(newApplication); _applications.AddOrUpdate(newApplication);
} }
} }

View File

@ -88,7 +88,7 @@ namespace Ryujinx.Ava.Utilities.Compat
_ => null _ => null
}; };
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out var dt)) if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out DateTime dt))
LastUpdated = dt; LastUpdated = dt;
return; return;

View File

@ -661,7 +661,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
if (!ShowDirtyHacks) if (!ShowDirtyHacks)
return; return;
var newHacks = EnabledHacks.Select(x => x.Hack) string newHacks = EnabledHacks.Select(x => x.Hack)
.JoinToString(", "); .JoinToString(", ");
if (newHacks != _lastHackCollection) if (newHacks != _lastHackCollection)

View File

@ -31,12 +31,12 @@ namespace Ryujinx.Ava.Utilities.Configuration
{ {
bool noFilter = e.NewValue.Length == 0; bool noFilter = e.NewValue.Length == 0;
foreach (var logClass in Enum.GetValues<LogClass>()) foreach (LogClass logClass in Enum.GetValues<LogClass>())
{ {
Logger.SetEnable(logClass, noFilter); Logger.SetEnable(logClass, noFilter);
} }
foreach (var logClass in e.NewValue) foreach (LogClass logClass in e.NewValue)
{ {
Logger.SetEnable(logClass, true); Logger.SetEnable(logClass, true);
} }

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Ava.Utilities
public static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase) public static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase)
{ {
var downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase); string downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
if (!File.Exists(downloadableContentJsonPath)) if (!File.Exists(downloadableContentJsonPath))
{ {
@ -31,7 +31,7 @@ namespace Ryujinx.Ava.Utilities
try try
{ {
var downloadableContentContainerList = JsonHelper.DeserializeFromFile(downloadableContentJsonPath, List<DownloadableContentContainer> downloadableContentContainerList = JsonHelper.DeserializeFromFile(downloadableContentJsonPath,
_serializerContext.ListDownloadableContentContainer); _serializerContext.ListDownloadableContentContainer);
return LoadDownloadableContents(vfs, downloadableContentContainerList); return LoadDownloadableContents(vfs, downloadableContentContainerList);
} }
@ -76,13 +76,13 @@ namespace Ryujinx.Ava.Utilities
downloadableContentContainerList.Add(container); downloadableContentContainerList.Add(container);
} }
var downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase); string downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
JsonHelper.SerializeToFile(downloadableContentJsonPath, downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer); JsonHelper.SerializeToFile(downloadableContentJsonPath, downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer);
} }
private static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContents(VirtualFileSystem vfs, List<DownloadableContentContainer> downloadableContentContainers) private static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContents(VirtualFileSystem vfs, List<DownloadableContentContainer> downloadableContentContainers)
{ {
var result = new List<(DownloadableContentModel, bool IsEnabled)>(); List<(DownloadableContentModel, bool IsEnabled)> result = new List<(DownloadableContentModel, bool IsEnabled)>();
foreach (DownloadableContentContainer downloadableContentContainer in downloadableContentContainers) foreach (DownloadableContentContainer downloadableContentContainer in downloadableContentContainers)
{ {
@ -105,7 +105,7 @@ namespace Ryujinx.Ava.Utilities
continue; continue;
} }
var content = new DownloadableContentModel(nca.Header.TitleId, DownloadableContentModel content = new DownloadableContentModel(nca.Header.TitleId,
downloadableContentContainer.ContainerPath, downloadableContentContainer.ContainerPath,
downloadableContentNca.FullPath); downloadableContentNca.FullPath);

View File

@ -18,11 +18,11 @@ namespace Ryujinx.Ava.Utilities
iconPath += ".ico"; iconPath += ".ico";
MemoryStream iconDataStream = new(iconData); MemoryStream iconDataStream = new(iconData);
using var image = SKBitmap.Decode(iconDataStream); using SKBitmap image = SKBitmap.Decode(iconDataStream);
image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High); image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High);
SaveBitmapAsIcon(image, iconPath); SaveBitmapAsIcon(image, iconPath);
var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0); Shortcut shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0);
shortcut.StringData.NameString = cleanedAppName; shortcut.StringData.NameString = cleanedAppName;
shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk")); shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk"));
} }
@ -31,12 +31,12 @@ namespace Ryujinx.Ava.Utilities
private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName) private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName)
{ {
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh"); string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh");
var desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop"); string desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop");
iconPath += ".png"; iconPath += ".png";
var image = SKBitmap.Decode(iconData); SKBitmap image = SKBitmap.Decode(iconData);
using var data = image.Encode(SKEncodedImageFormat.Png, 100); using SKData data = image.Encode(SKEncodedImageFormat.Png, 100);
using var file = File.OpenWrite(iconPath); using FileStream file = File.OpenWrite(iconPath);
data.SaveTo(file); data.SaveTo(file);
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop")); using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop"));
@ -47,8 +47,8 @@ namespace Ryujinx.Ava.Utilities
private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName) private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName)
{ {
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"); string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
var plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist"); string plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist");
var shortcutScript = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-launch-script.sh"); string shortcutScript = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-launch-script.sh");
// Macos .App folder // Macos .App folder
string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents"); string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents");
string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS"); string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS");
@ -77,9 +77,9 @@ namespace Ryujinx.Ava.Utilities
} }
const string IconName = "icon.png"; const string IconName = "icon.png";
var image = SKBitmap.Decode(iconData); SKBitmap image = SKBitmap.Decode(iconData);
using var data = image.Encode(SKEncodedImageFormat.Png, 100); using SKData data = image.Encode(SKEncodedImageFormat.Png, 100);
using var file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName)); using FileStream file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName));
data.SaveTo(file); data.SaveTo(file);
// plist file // plist file
@ -124,7 +124,7 @@ namespace Ryujinx.Ava.Utilities
private static string GetArgsString(string appFilePath, string applicationId) private static string GetArgsString(string appFilePath, string applicationId)
{ {
// args are first defined as a list, for easier adjustments in the future // args are first defined as a list, for easier adjustments in the future
var argsList = new List<string>(); List<string> argsList = new List<string>();
if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg)) if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg))
{ {
@ -157,7 +157,7 @@ namespace Ryujinx.Ava.Utilities
fs.Write(header); fs.Write(header);
// Writing actual data // Writing actual data
using var data = source.Encode(SKEncodedImageFormat.Png, 100); using SKData data = source.Encode(SKEncodedImageFormat.Png, 100);
data.SaveTo(fs); data.SaveTo(fs);
// Getting data length (file length minus header) // Getting data length (file length minus header)
long dataLength = fs.Length - header.Length; long dataLength = fs.Length - header.Length;

View File

@ -16,7 +16,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
if (cpuName == null) if (cpuName == null)
{ {
var cpuDict = new Dictionary<string, string>(StringComparer.Ordinal) Dictionary<string, string> cpuDict = new Dictionary<string, string>(StringComparer.Ordinal)
{ {
["model name"] = null, ["model name"] = null,
["Processor"] = null, ["Processor"] = null,
@ -28,7 +28,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
cpuName = cpuDict["model name"] ?? cpuDict["Processor"] ?? cpuDict["Hardware"] ?? "Unknown"; cpuName = cpuDict["model name"] ?? cpuDict["Processor"] ?? cpuDict["Hardware"] ?? "Unknown";
} }
var memDict = new Dictionary<string, string>(StringComparer.Ordinal) Dictionary<string, string> memDict = new Dictionary<string, string>(StringComparer.Ordinal)
{ {
["MemTotal"] = null, ["MemTotal"] = null,
["MemAvailable"] = null, ["MemAvailable"] = null,

View File

@ -40,10 +40,10 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
static ulong GetVMInfoAvailableMemory() static ulong GetVMInfoAvailableMemory()
{ {
var port = mach_host_self(); uint port = mach_host_self();
uint pageSize = 0; uint pageSize = 0;
var result = host_page_size(port, ref pageSize); int result = host_page_size(port, ref pageSize);
if (result != 0) if (result != 0)
{ {

View File

@ -34,7 +34,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
if (cpuObjs != null) if (cpuObjs != null)
{ {
foreach (var cpuObj in cpuObjs) foreach (ManagementBaseObject cpuObj in cpuObjs)
{ {
return cpuObj["Name"].ToString().Trim(); return cpuObj["Name"].ToString().Trim();
} }

View File

@ -30,7 +30,7 @@ namespace Ryujinx.Ava.Utilities
public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase) public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
{ {
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase); string titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
if (!File.Exists(titleUpdatesJsonPath)) if (!File.Exists(titleUpdatesJsonPath))
{ {
@ -39,7 +39,7 @@ namespace Ryujinx.Ava.Utilities
try try
{ {
var titleUpdateWindowData = JsonHelper.DeserializeFromFile(titleUpdatesJsonPath, _serializerContext.TitleUpdateMetadata); TitleUpdateMetadata titleUpdateWindowData = JsonHelper.DeserializeFromFile(titleUpdatesJsonPath, _serializerContext.TitleUpdateMetadata);
return LoadTitleUpdates(vfs, titleUpdateWindowData, applicationIdBase); return LoadTitleUpdates(vfs, titleUpdateWindowData, applicationIdBase);
} }
catch catch
@ -51,7 +51,7 @@ namespace Ryujinx.Ava.Utilities
public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates) public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
{ {
var titleUpdateWindowData = new TitleUpdateMetadata TitleUpdateMetadata titleUpdateWindowData = new TitleUpdateMetadata
{ {
Selected = string.Empty, Selected = string.Empty,
Paths = [], Paths = [],
@ -73,13 +73,13 @@ namespace Ryujinx.Ava.Utilities
} }
} }
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase); string titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata); JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
} }
private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase) private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
{ {
var result = new List<(TitleUpdateModel, bool IsSelected)>(); List<(TitleUpdateModel, bool IsSelected)> result = new List<(TitleUpdateModel, bool IsSelected)>();
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid ? IntegrityCheckLevel.ErrorOnInvalid
@ -115,8 +115,8 @@ namespace Ryujinx.Ava.Utilities
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None) nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None)
.ThrowIfFailure(); .ThrowIfFailure();
var displayVersion = controlData.DisplayVersionString.ToString(); string displayVersion = controlData.DisplayVersionString.ToString();
var update = new TitleUpdateModel(content.ApplicationId, content.Version.Version, TitleUpdateModel update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
displayVersion, path); displayVersion, path);
result.Add((update, path == titleUpdateMetadata.Selected)); result.Add((update, path == titleUpdateMetadata.Selected));

View File

@ -139,10 +139,10 @@ namespace Ryujinx.Ava.Utilities
// An input string can either look like "01:23:45" or "1d, 01:23:45" if the timespan represents a duration of more than a day. // An input string can either look like "01:23:45" or "1d, 01:23:45" if the timespan represents a duration of more than a day.
// Here, we split the input string to check if it's the former or the latter. // Here, we split the input string to check if it's the former or the latter.
var valueSplit = timeSpanString.Split(", "); string[] valueSplit = timeSpanString.Split(", ");
if (valueSplit.Length > 1) if (valueSplit.Length > 1)
{ {
var dayPart = valueSplit[0].Split("d")[0]; string dayPart = valueSplit[0].Split("d")[0];
if (int.TryParse(dayPart, out int days)) if (int.TryParse(dayPart, out int days))
{ {
returnTimeSpan = returnTimeSpan.Add(TimeSpan.FromDays(days)); returnTimeSpan = returnTimeSpan.Add(TimeSpan.FromDays(days));