diff options
| author | TSRBerry <20988865+TSRBerry@users.noreply.github.com> | 2023-07-07 23:03:27 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-07 23:03:27 +0200 |
| commit | 6c515e18228b93c4d856129ba55a692e830cbdaa (patch) | |
| tree | 661a3be3cf71c5276e82cb4fcc13b39f9e7f9f90 /src/Ryujinx.Ava/UI/ViewModels | |
| parent | 8a363b5df2387bd254a3dd48bfd3c9884ff74dab (diff) | |
[Ryujinx.Ava] Address dotnet-format issues (#5361)
* dotnet format style --severity info
Some changes were manually reverted.
* dotnet format analyzers --serverity info
Some changes have been minimally adapted.
* Restore a few unused methods and variables
* Silence dotnet format IDE0060 warnings
* Silence dotnet format IDE0052 warnings
* Silence dotnet format IDE0059 warnings
* Address or silence dotnet format IDE1006 warnings
* Address dotnet format CA1816 warnings
* Address dotnet format CA1822 warnings
* Address or silence dotnet format CA1069 warnings
* Make dotnet format succeed in style mode
* Address dotnet format CA1401 warnings
* Address remaining dotnet format analyzer warnings
* Address review comments
* dotnet-format fixes after rebase
* Address most dotnet format whitespace warnings
* Apply dotnet format whitespace formatting
A few of them have been manually reverted and the corresponding warning was silenced
* Format if-blocks correctly
* Another rebase, another dotnet format run
* Run dotnet format whitespace after rebase
* Run dotnet format style after rebase
* Run dotnet format after rebase and remove unused usings
- analyzers
- style
- whitespace
* Add comments to disabled warnings
* Remove a few unused parameters
* Simplify properties and array initialization, Use const when possible, Remove trailing commas
* Start working on disabled warnings
* Fix and silence a few dotnet-format warnings again
* Address IDE0260 warnings
* Address a few disabled IDE0060 warnings
* Silence IDE0060 in .editorconfig
* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"
This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.
* dotnet format whitespace after rebase
* dotnet format pass with new editorconfig
* Fix naming style issues
* Apply suggestions from code review
Co-authored-by: Ac_K <Acoustik666@gmail.com>
* Revert one suggestion
* Second dotnet format pass and fix build issues
* Final pass of dotnet format
* Add trailing commas
* Fix formatting issues
* Keep unnecessary assignment in IconColorPicker.cs
* Use using declarations and extend resource lifetimes
* Fix rebase issues
* Adjust comment spacing
* Fix typo
* Fix naming issues
* Apply suggestions from code review
Co-authored-by: Ac_K <Acoustik666@gmail.com>
* Revert unintentional change
* Remove unused file
* Remove static keyword from ViewModels
Binding of static members doesn't work and is silently ignored.
---------
Co-authored-by: Ac_K <Acoustik666@gmail.com>
Diffstat (limited to 'src/Ryujinx.Ava/UI/ViewModels')
15 files changed, 283 insertions, 649 deletions
diff --git a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs index 479411cb..fddcd71a 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs @@ -1,5 +1,6 @@ using Avalonia; using Avalonia.Media.Imaging; +using Avalonia.Platform; using Avalonia.Threading; using Ryujinx.Ava.Common.Locale; using Ryujinx.Common.Utilities; @@ -87,7 +88,7 @@ namespace Ryujinx.Ava.UI.ViewModels { Version = Program.Version; - var assets = AvaloniaLocator.Current.GetService<Avalonia.Platform.IAssetLoader>(); + var assets = AvaloniaLocator.Current.GetService<IAssetLoader>(); if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light") { @@ -130,4 +131,4 @@ namespace Ryujinx.Ava.UI.ViewModels } } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs index ecd425ef..3138dd14 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs @@ -18,7 +18,6 @@ using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext; namespace Ryujinx.Ava.UI.ViewModels { @@ -44,7 +43,7 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _useRandomUuid; private string _usage; - private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId) { @@ -52,7 +51,7 @@ namespace Ryujinx.Ava.UI.ViewModels _httpClient = new HttpClient { - Timeout = TimeSpan.FromSeconds(30) + Timeout = TimeSpan.FromSeconds(30), }; LastScannedAmiiboId = lastScannedAmiiboId; @@ -185,6 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels public void Dispose() { + GC.SuppressFinalize(this); _httpClient.Dispose(); } @@ -196,7 +196,7 @@ namespace Ryujinx.Ava.UI.ViewModels { amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath); - if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated)) + if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated)) { amiiboJsonString = await DownloadAmiiboJson(); } @@ -215,7 +215,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - _amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo; + _amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo; _amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList(); ParseAmiiboData(); @@ -426,18 +426,17 @@ namespace Ryujinx.Ava.UI.ViewModels if (response.IsSuccessStatusCode) { byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); - using (MemoryStream memoryStream = new(amiiboPreviewBytes)) - { - Bitmap bitmap = new(memoryStream); + using MemoryStream memoryStream = new(amiiboPreviewBytes); + + Bitmap bitmap = new(memoryStream); - double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, + double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, AmiiboImageSize / bitmap.Size.Height); - int resizeHeight = (int)(bitmap.Size.Height * ratio); - int resizeWidth = (int)(bitmap.Size.Width * ratio); + int resizeHeight = (int)(bitmap.Size.Height * ratio); + int resizeWidth = (int)(bitmap.Size.Width * ratio); - AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight)); - } + AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight)); } else { @@ -447,15 +446,14 @@ namespace Ryujinx.Ava.UI.ViewModels private void ResetAmiiboPreview() { - using (MemoryStream memoryStream = new(_amiiboLogoBytes)) - { - Bitmap bitmap = new(memoryStream); + using MemoryStream memoryStream = new(_amiiboLogoBytes); - AmiiboImage = bitmap; - } + Bitmap bitmap = new(memoryStream); + + AmiiboImage = bitmap; } - private async void ShowInfoDialog() + private static async void ShowInfoDialog() { await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage], @@ -464,4 +462,4 @@ namespace Ryujinx.Ava.UI.ViewModels LocaleManager.Instance[LocaleKeys.RyujinxInfo]); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/AvatarProfileViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AvatarProfileViewModel.cs deleted file mode 100644 index b2b31014..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/AvatarProfileViewModel.cs +++ /dev/null @@ -1,363 +0,0 @@ -using Avalonia.Media; -using DynamicData; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Ncm; -using LibHac.Tools.Fs; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.UI.Models; -using Ryujinx.HLE.FileSystem; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Color = Avalonia.Media.Color; - -namespace Ryujinx.Ava.UI.ViewModels -{ - internal class AvatarProfileViewModel : BaseModel, IDisposable - { - private const int MaxImageTasks = 4; - - private static readonly Dictionary<string, byte[]> _avatarStore = new(); - private static bool _isPreloading; - private static Action _loadCompleteAction; - - private ObservableCollection<ProfileImageModel> _images; - private Color _backgroundColor = Colors.White; - - private int _selectedIndex; - private int _imagesLoaded; - private bool _isActive; - private byte[] _selectedImage; - private bool _isIndeterminate = true; - - public bool IsActive - { - get => _isActive; - set => _isActive = value; - } - - public AvatarProfileViewModel() - { - _images = new ObservableCollection<ProfileImageModel>(); - } - - public AvatarProfileViewModel(Action loadCompleteAction) - { - _images = new ObservableCollection<ProfileImageModel>(); - - if (_isPreloading) - { - _loadCompleteAction = loadCompleteAction; - } - else - { - ReloadImages(); - } - } - - public Color BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value; - - IsActive = false; - - ReloadImages(); - } - } - - public ObservableCollection<ProfileImageModel> Images - { - get => _images; - set - { - _images = value; - OnPropertyChanged(); - } - } - - public bool IsIndeterminate - { - get => _isIndeterminate; - set - { - _isIndeterminate = value; - - OnPropertyChanged(); - } - } - - public int ImageCount => _avatarStore.Count; - - public int ImagesLoaded - { - get => _imagesLoaded; - set - { - _imagesLoaded = value; - OnPropertyChanged(); - } - } - - public int SelectedIndex - { - get => _selectedIndex; - set - { - _selectedIndex = value; - - if (_selectedIndex == -1) - { - SelectedImage = null; - } - else - { - SelectedImage = _images[_selectedIndex].Data; - } - - OnPropertyChanged(); - } - } - - public byte[] SelectedImage - { - get => _selectedImage; - private set => _selectedImage = value; - } - - public void ReloadImages() - { - if (_isPreloading) - { - IsIndeterminate = false; - return; - } - Task.Run(() => - { - IsActive = true; - - Images.Clear(); - int selectedIndex = _selectedIndex; - int index = 0; - - ImagesLoaded = 0; - IsIndeterminate = false; - - var keys = _avatarStore.Keys.ToList(); - - var newImages = new List<ProfileImageModel>(); - var tasks = new List<Task>(); - - for (int i = 0; i < MaxImageTasks; i++) - { - var start = i; - tasks.Add(Task.Run(() => ImageTask(start))); - } - - Task.WaitAll(tasks.ToArray()); - - Images.AddRange(newImages); - - void ImageTask(int start) - { - for (int i = start; i < keys.Count; i += MaxImageTasks) - { - if (!IsActive) - { - return; - } - - var key = keys[i]; - var image = _avatarStore[keys[i]]; - - var data = ProcessImage(image); - newImages.Add(new ProfileImageModel(key, data)); - if (index++ == selectedIndex) - { - SelectedImage = data; - } - - Interlocked.Increment(ref _imagesLoaded); - OnPropertyChanged(nameof(ImagesLoaded)); - } - } - }); - } - - private byte[] ProcessImage(byte[] data) - { - using (MemoryStream streamJpg = new()) - { - Image avatarImage = Image.Load(data, new PngDecoder()); - - avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(BackgroundColor.R, - BackgroundColor.G, - BackgroundColor.B, - BackgroundColor.A))); - avatarImage.SaveAsJpeg(streamJpg); - - return streamJpg.ToArray(); - } - } - - public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem) - { - try - { - if (_avatarStore.Count > 0) - { - return; - } - - _isPreloading = true; - - string contentPath = - contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, - NcaContentType.Data); - string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath); - - if (!string.IsNullOrWhiteSpace(avatarPath)) - { - using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open)) - { - Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); - IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - foreach (DirectoryEntryEx item in romfs.EnumerateEntries()) - { - // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy. - if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && - item.FullPath.Contains("szs")) - { - using var file = new UniqueRef<IFile>(); - - romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read) - .ThrowIfFailure(); - - using (MemoryStream stream = new()) - using (MemoryStream streamPng = new()) - { - file.Get.AsStream().CopyTo(stream); - - stream.Position = 0; - - Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256); - - avatarImage.SaveAsPng(streamPng); - - _avatarStore.Add(item.FullPath, streamPng.ToArray()); - } - } - } - } - } - } - finally - { - _isPreloading = false; - _loadCompleteAction?.Invoke(); - } - } - - private static byte[] DecompressYaz0(Stream stream) - { - using (BinaryReader reader = new(stream)) - { - reader.ReadInt32(); // Magic - - uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32()); - - reader.ReadInt64(); // Padding - - byte[] input = new byte[stream.Length - stream.Position]; - stream.Read(input, 0, input.Length); - - uint inputOffset = 0; - - byte[] output = new byte[decodedLength]; - uint outputOffset = 0; - - ushort mask = 0; - byte header = 0; - - while (outputOffset < decodedLength) - { - if ((mask >>= 1) == 0) - { - header = input[inputOffset++]; - mask = 0x80; - } - - if ((header & mask) != 0) - { - if (outputOffset == output.Length) - { - break; - } - - output[outputOffset++] = input[inputOffset++]; - } - else - { - byte byte1 = input[inputOffset++]; - byte byte2 = input[inputOffset++]; - - uint dist = (uint)((byte1 & 0xF) << 8) | byte2; - uint position = outputOffset - (dist + 1); - - uint length = (uint)byte1 >> 4; - if (length == 0) - { - length = (uint)input[inputOffset++] + 0x12; - } - else - { - length += 2; - } - - uint gap = outputOffset - position; - uint nonOverlappingLength = length; - - if (nonOverlappingLength > gap) - { - nonOverlappingLength = gap; - } - - Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength); - outputOffset += nonOverlappingLength; - position += nonOverlappingLength; - length -= nonOverlappingLength; - - while (length-- > 0) - { - output[outputOffset++] = output[position++]; - } - } - } - - return output; - } - } - - public void Dispose() - { - _loadCompleteAction = null; - IsActive = false; - } - } -}
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs b/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs index 5a3717fd..0ff72dbc 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs @@ -12,4 +12,4 @@ namespace Ryujinx.Ava.UI.ViewModels PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs index fda58504..c0c62532 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs @@ -1,3 +1,4 @@ +using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -44,15 +45,14 @@ namespace Ryujinx.Ava.UI.ViewModels private PlayerIndex _playerId; private int _controller; - private int _controllerNumber = 0; + private int _controllerNumber; private string _controllerImage; private int _device; private object _configuration; private string _profileName; private bool _isLoaded; - private readonly UserControl _owner; - private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public IGamepadDriver AvaloniaKeyboardDriver { get; } public IGamepad SelectedGamepad { get; private set; } @@ -176,11 +176,11 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - SvgImage image = new SvgImage(); + SvgImage image = new(); if (!string.IsNullOrWhiteSpace(_controllerImage)) { - SvgSource source = new SvgSource(); + SvgSource source = new(); source.Load(EmbeddedResources.GetStream(_controllerImage)); @@ -234,22 +234,18 @@ namespace Ryujinx.Ava.UI.ViewModels public ControllerInputViewModel(UserControl owner) : this() { - _owner = owner; - if (Program.PreviewerDetached) { _mainWindow = - (MainWindow)((IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current + (MainWindow)((IClassicDesktopStyleApplicationLifetime)Application.Current .ApplicationLifetime).MainWindow; AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); _mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; - if (_mainWindow.ViewModel.AppHost != null) - { - _mainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates(); - } + + _mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates(); _isLoaded = false; @@ -351,7 +347,8 @@ namespace Ryujinx.Ava.UI.ViewModels { return; } - else if (type == DeviceType.Keyboard) + + if (type == DeviceType.Keyboard) { if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver) { @@ -448,7 +445,7 @@ namespace Ryujinx.Ava.UI.ViewModels const string Hyphen = "-"; const int Offset = 1; - return str.Substring(str.IndexOf(Hyphen) + Offset); + return str[(str.IndexOf(Hyphen) + Offset)..]; } public void LoadDevices() @@ -562,7 +559,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonL = Key.E, ButtonZl = Key.Q, ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound + ButtonSr = Key.Unbound, }, LeftJoyconStick = new JoyconConfigKeyboardStick<Key> @@ -571,7 +568,7 @@ namespace Ryujinx.Ava.UI.ViewModels StickDown = Key.S, StickLeft = Key.A, StickRight = Key.D, - StickButton = Key.F + StickButton = Key.F, }, RightJoycon = new RightJoyconCommonConfig<Key> { @@ -583,7 +580,7 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonR = Key.U, ButtonZr = Key.O, ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound + ButtonSr = Key.Unbound, }, RightJoyconStick = new JoyconConfigKeyboardStick<Key> { @@ -591,8 +588,8 @@ namespace Ryujinx.Ava.UI.ViewModels StickDown = Key.K, StickLeft = Key.J, StickRight = Key.L, - StickButton = Key.H - } + StickButton = Key.H, + }, }; } else if (activeDevice.Type == DeviceType.Controller) @@ -622,14 +619,14 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonL = ConfigGamepadInputId.LeftShoulder, ButtonZl = ConfigGamepadInputId.LeftTrigger, ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound + ButtonSr = ConfigGamepadInputId.Unbound, }, LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> { Joystick = ConfigStickInputId.Left, StickButton = ConfigGamepadInputId.LeftStick, InvertStickX = false, - InvertStickY = false + InvertStickY = false, }, RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId> { @@ -641,28 +638,28 @@ namespace Ryujinx.Ava.UI.ViewModels ButtonR = ConfigGamepadInputId.RightShoulder, ButtonZr = ConfigGamepadInputId.RightTrigger, ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound + ButtonSr = ConfigGamepadInputId.Unbound, }, RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> { Joystick = ConfigStickInputId.Right, StickButton = ConfigGamepadInputId.RightStick, InvertStickX = false, - InvertStickY = false + InvertStickY = false, }, Motion = new StandardMotionConfigController { MotionBackend = MotionInputBackendType.GamepadDriver, EnableMotion = true, Sensitivity = 100, - GyroDeadzone = 1 + GyroDeadzone = 1, }, Rumble = new RumbleConfigController { StrongRumble = 1f, WeakRumble = 1f, - EnableRumble = false - } + EnableRumble = false, + }, }; } else @@ -709,7 +706,7 @@ namespace Ryujinx.Ava.UI.ViewModels try { - config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig); + config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig); } catch (JsonException) { } catch (InvalidOperationException) @@ -754,37 +751,35 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - else - { - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - InputConfig config = null; + bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - if (IsKeyboard) - { - config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig(); - } - else if (IsController) - { - config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig(); - } - - config.ControllerType = Controllers[_controller].Type; - - string jsonString = JsonHelper.Serialize(config, SerializerContext.InputConfig); + if (validFileName) + { + string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - await File.WriteAllTextAsync(path, jsonString); + InputConfig config = null; - LoadProfiles(); + if (IsKeyboard) + { + config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig(); } - else + else if (IsController) { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig(); } + + config.ControllerType = Controllers[_controller].Type; + + string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); + + await File.WriteAllTextAsync(path, jsonString); + + LoadProfiles(); + } + else + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); } } @@ -887,6 +882,8 @@ namespace Ryujinx.Ava.UI.ViewModels public void Dispose() { + GC.SuppressFinalize(this); + _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; @@ -897,4 +894,4 @@ namespace Ryujinx.Ava.UI.ViewModels AvaloniaKeyboardDriver.Dispose(); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs index 1d7da9a4..f2f56947 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Application = Avalonia.Application; using Path = System.IO.Path; namespace Ryujinx.Ava.UI.ViewModels @@ -29,18 +30,17 @@ namespace Ryujinx.Ava.UI.ViewModels public class DownloadableContentManagerViewModel : BaseModel { private readonly List<DownloadableContentContainer> _downloadableContentContainerList; - private readonly string _downloadableContentJsonPath; + private readonly string _downloadableContentJsonPath; - private VirtualFileSystem _virtualFileSystem; + private readonly VirtualFileSystem _virtualFileSystem; private AvaloniaList<DownloadableContentModel> _downloadableContents = new(); private AvaloniaList<DownloadableContentModel> _views = new(); private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new(); private string _search; - private ulong _titleId; - private string _titleName; + private readonly ulong _titleId; - private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public AvaloniaList<DownloadableContentModel> DownloadableContents { @@ -90,18 +90,17 @@ namespace Ryujinx.Ava.UI.ViewModels get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); } - public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) + public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) { _virtualFileSystem = virtualFileSystem; - _titleId = titleId; - _titleName = titleName; + _titleId = titleId; _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json"); try { - _downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, SerializerContext.ListDownloadableContentContainer); + _downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, _serializerContext.ListDownloadableContentContainer); } catch { @@ -132,7 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath); if (nca != null) - { + { var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath, @@ -196,19 +195,19 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { - OpenFileDialog dialog = new OpenFileDialog() + OpenFileDialog dialog = new() { - Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], - AllowMultiple = true + Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], + AllowMultiple = true, }; dialog.Filters.Add(new FileDialogFilter { - Name = "NSP", - Extensions = { "nsp" } + Name = "NSP", + Extensions = { "nsp" }, }); - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { string[] files = await dialog.ShowAsync(desktop.MainWindow); @@ -231,8 +230,8 @@ namespace Ryujinx.Ava.UI.ViewModels using FileStream containerFile = File.OpenRead(path); - PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); - bool containsDownloadableContent = false; + PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); + bool containsDownloadableContent = false; _virtualFileSystem.ImportTickets(partitionFileSystem); @@ -313,16 +312,16 @@ namespace Ryujinx.Ava.UI.ViewModels container = new DownloadableContentContainer { - ContainerPath = downloadableContent.ContainerPath, - DownloadableContentNcaList = new List<DownloadableContentNca>() + ContainerPath = downloadableContent.ContainerPath, + DownloadableContentNcaList = new List<DownloadableContentNca>(), }; } container.DownloadableContentNcaList.Add(new DownloadableContentNca { - Enabled = downloadableContent.Enabled, - TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16), - FullPath = downloadableContent.FullPath + Enabled = downloadableContent.Enabled, + TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16), + FullPath = downloadableContent.FullPath, }); } @@ -331,8 +330,8 @@ namespace Ryujinx.Ava.UI.ViewModels _downloadableContentContainerList.Add(container); } - JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, SerializerContext.ListDownloadableContentContainer); + JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs index 0976e2fa..e8d68f76 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs @@ -1,3 +1,4 @@ +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; @@ -12,6 +13,7 @@ using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; +using Ryujinx.Ava.UI.Models.Generic; using Ryujinx.Ava.UI.Renderer; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; @@ -23,6 +25,7 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.Ui; +using Ryujinx.Modules; using Ryujinx.Ui.App.Common; using Ryujinx.Ui.Common; using Ryujinx.Ui.Common.Configuration; @@ -34,7 +37,10 @@ using System.Collections.ObjectModel; using System.IO; using System.Threading; using System.Threading.Tasks; -using Path = System.IO.Path; +using Image = SixLabors.ImageSharp.Image; +using InputManager = Ryujinx.Input.HLE.InputManager; +using Key = Ryujinx.Input.Key; +using MissingKeyException = LibHac.Common.Keys.MissingKeyException; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; namespace Ryujinx.Ava.UI.ViewModels @@ -89,7 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels private Cursor _cursor; private string _title; private string _currentEmulatedGamePath; - private AutoResetEvent _rendererWaitEvent; + private readonly AutoResetEvent _rendererWaitEvent; private WindowState _windowState; private double _windowWidth; private double _windowHeight; @@ -128,7 +134,7 @@ namespace Ryujinx.Ava.UI.ViewModels ApplicationLibrary applicationLibrary, VirtualFileSystem virtualFileSystem, AccountManager accountManager, - Ryujinx.Input.HLE.InputManager inputManager, + InputManager inputManager, UserChannelPersistence userChannelPersistence, LibHacHorizonManager libHacHorizonManager, IHostUiHandler uiHandler, @@ -152,7 +158,7 @@ namespace Ryujinx.Ava.UI.ViewModels TopLevel = topLevel; } -#region Properties + #region Properties public string SearchText { @@ -177,7 +183,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool CanUpdate { - get => _canUpdate && EnableNonGameRunningControls && Modules.Updater.CanUpdate(false); + get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false); set { _canUpdate = value; @@ -343,11 +349,11 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public bool OpenUserSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0; + public bool OpenUserSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0; - public bool OpenDeviceSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; + public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; - public bool OpenBcatSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; + public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; public string LoadHeading { @@ -888,7 +894,7 @@ namespace Ryujinx.Ava.UI.ViewModels public ApplicationLibrary ApplicationLibrary { get; private set; } public VirtualFileSystem VirtualFileSystem { get; private set; } public AccountManager AccountManager { get; private set; } - public Ryujinx.Input.HLE.InputManager InputManager { get; private set; } + public InputManager InputManager { get; private set; } public UserChannelPersistence UserChannelPersistence { get; private set; } public Action<bool> ShowLoading { get; private set; } public Action<bool> SwitchToGameControl { get; private set; } @@ -911,15 +917,16 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3; public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4; -#endregion + #endregion -#region PrivateMethods + #region PrivateMethods private IComparer<ApplicationData> GetComparer() { return SortMode switch { - ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending), +#pragma warning disable IDE0055 // Disable formatting + ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending), ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes) : SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes), ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum) @@ -935,6 +942,7 @@ namespace Ryujinx.Ava.UI.ViewModels ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) : SortExpressionComparer<ApplicationData>.Descending(app => app.Path), _ => null, +#pragma warning restore IDE0055 }; } @@ -1023,7 +1031,7 @@ namespace Ryujinx.Ava.UI.ViewModels // Purge Applet Cache. - DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache")); + DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache")); if (miiEditorCacheFolder.Exists) { @@ -1044,18 +1052,21 @@ namespace Ryujinx.Ava.UI.ViewModels { RefreshFirmwareStatus(); } - }) { Name = "GUI.FirmwareInstallerThread" }; + }) + { + Name = "GUI.FirmwareInstallerThread", + }; thread.Start(); } } - catch (LibHac.Common.Keys.MissingKeyException ex) + catch (MissingKeyException ex) { - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { Logger.Error?.Print(LogClass.Application, ex.ToString()); - async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, (desktop.MainWindow as MainWindow)); + static async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys); Dispatcher.UIThread.Post(Action); } @@ -1120,7 +1131,7 @@ namespace Ryujinx.Ava.UI.ViewModels private void PrepareLoadScreen() { using MemoryStream stream = new(SelectedIcon); - using var gameIconBmp = SixLabors.ImageSharp.Image.Load<Bgra32>(stream); + using var gameIconBmp = Image.Load<Bgra32>(stream); var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>(); @@ -1175,7 +1186,7 @@ namespace Ryujinx.Ava.UI.ViewModels { Dispatcher.UIThread.InvokeAsync(() => { - Avalonia.Application.Current.Styles.TryGetResource(args.VSyncEnabled + Application.Current.Styles.TryGetResource(args.VSyncEnabled ? "VsyncEnabled" : "VsyncDisabled", out object color); @@ -1204,11 +1215,11 @@ namespace Ryujinx.Ava.UI.ViewModels _rendererWaitEvent.Set(); } -#endregion + #endregion -#region PublicMethods + #region PublicMethods - public void SetUIProgressHandlers(Switch emulationContext) + public void SetUiProgressHandlers(Switch emulationContext) { if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null) { @@ -1222,17 +1233,17 @@ namespace Ryujinx.Ava.UI.ViewModels public void LoadConfigurableHotKeys() { - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) + if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) { ShowUiKey = new KeyGesture(showUiKey); } - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) + if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) { ScreenshotKey = new KeyGesture(screenshotKey); } - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) + if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) { PauseKey = new KeyGesture(pauseKey); } @@ -1260,12 +1271,12 @@ namespace Ryujinx.Ava.UI.ViewModels public async void InstallFirmwareFromFile() { - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { OpenFileDialog dialog = new() { AllowMultiple = false }; dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } }); - dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } }); - dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } }); + dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } }); + dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } }); string[] file = await dialog.ShowAsync(desktop.MainWindow); @@ -1278,7 +1289,7 @@ namespace Ryujinx.Ava.UI.ViewModels public async void InstallFirmwareFromFolder() { - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { OpenFolderDialog dialog = new(); @@ -1327,7 +1338,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public void ChangeLanguage(object languageCode) + public static void ChangeLanguage(object languageCode) { LocaleManager.Instance.LoadLanguage((string)languageCode); @@ -1342,6 +1353,7 @@ namespace Ryujinx.Ava.UI.ViewModels { _ = fileType switch { +#pragma warning disable IDE0055 // Disable formatting "NSP" => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP, "PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0, "XCI" => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI, @@ -1349,6 +1361,7 @@ namespace Ryujinx.Ava.UI.ViewModels "NRO" => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO, "NSO" => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO, _ => throw new ArgumentOutOfRangeException(fileType), +#pragma warning restore IDE0055 }; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); @@ -1371,9 +1384,9 @@ namespace Ryujinx.Ava.UI.ViewModels { Applications.Clear(); - StatusBarVisible = true; + StatusBarVisible = true; StatusBarProgressMaximum = 0; - StatusBarProgressValue = 0; + StatusBarProgressValue = 0; LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0); }); @@ -1383,11 +1396,11 @@ namespace Ryujinx.Ava.UI.ViewModels public async void OpenFile() { - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { OpenFileDialog dialog = new() { - Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle] + Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], }; dialog.Filters.Add(new FileDialogFilter @@ -1400,16 +1413,18 @@ namespace Ryujinx.Ava.UI.ViewModels "xci", "nca", "nro", - "nso" - } + "nso", + }, }); +#pragma warning disable IDE0055 // Disable formatting dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } }); dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } }); dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } }); dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } }); +#pragma warning restore IDE0055 string[] files = await dialog.ShowAsync(desktop.MainWindow); @@ -1422,11 +1437,11 @@ namespace Ryujinx.Ava.UI.ViewModels public async void OpenFolder() { - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { OpenFolderDialog dialog = new() { - Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle] + Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle], }; string folder = await dialog.ShowAsync(desktop.MainWindow); @@ -1458,10 +1473,7 @@ namespace Ryujinx.Ava.UI.ViewModels Logger.RestartTime(); - if (SelectedIcon == null) - { - SelectedIcon = ApplicationLibrary.GetApplicationIcon(path); - } + SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path); PrepareLoadScreen(); @@ -1495,7 +1507,7 @@ namespace Ryujinx.Ava.UI.ViewModels if (string.IsNullOrWhiteSpace(titleName)) { LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, AppHost.Device.Processes.ActiveApplication.Name); - TitleName = AppHost.Device.Processes.ActiveApplication.Name; + TitleName = AppHost.Device.Processes.ActiveApplication.Name; } SwitchToRenderer(startFullscreen); @@ -1521,7 +1533,7 @@ namespace Ryujinx.Ava.UI.ViewModels }); } - public void UpdateGameMetadata(string titleId) + public static void UpdateGameMetadata(string titleId) { ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => { @@ -1675,6 +1687,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } -#endregion + #endregion } } diff --git a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs index d57ccc6b..0b12a51f 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs @@ -90,4 +90,4 @@ namespace Ryujinx.Ava.UI.ViewModels } } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs index 2d53968f..49de1993 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs @@ -24,4 +24,4 @@ namespace Ryujinx.Ava.UI.ViewModels } } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index 0a2ffae3..a9eb9c61 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -18,7 +18,6 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Configuration.System; -using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -248,7 +247,7 @@ namespace Ryujinx.Ava.UI.ViewModels public AvaloniaList<string> NetworkInterfaceList { - get => new AvaloniaList<string>(_networkInterfaces.Keys); + get => new(_networkInterfaces.Keys); } public KeyboardHotkeys KeyboardHotkeys @@ -561,7 +560,7 @@ namespace Ryujinx.Ava.UI.ViewModels _directoryChanged = false; } - public void RevertIfNotSaved() + private static void RevertIfNotSaved() { Program.ReloadConfig(); } @@ -583,4 +582,4 @@ namespace Ryujinx.Ava.UI.ViewModels CloseWindow?.Invoke(); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs index 1f4e3c62..740d888b 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs @@ -1,3 +1,4 @@ +using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -16,7 +17,6 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; using Ryujinx.Ui.App.Common; using System; using System.Collections.Generic; @@ -29,17 +29,16 @@ namespace Ryujinx.Ava.UI.ViewModels { public class TitleUpdateViewModel : BaseModel { - public TitleUpdateMetadata _titleUpdateWindowData; - public readonly string _titleUpdateJsonPath; - private VirtualFileSystem _virtualFileSystem { get; } - private ulong _titleId { get; } - private string _titleName { get; } + public TitleUpdateMetadata TitleUpdateWindowData; + public readonly string TitleUpdateJsonPath; + private VirtualFileSystem VirtualFileSystem { get; } + private ulong TitleId { get; } private AvaloniaList<TitleUpdateModel> _titleUpdates = new(); private AvaloniaList<object> _views = new(); private object _selectedUpdate; - private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public AvaloniaList<TitleUpdateModel> TitleUpdates { @@ -71,27 +70,26 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) + public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) { - _virtualFileSystem = virtualFileSystem; + VirtualFileSystem = virtualFileSystem; - _titleId = titleId; - _titleName = titleName; + TitleId = titleId; - _titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); + TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); try { - _titleUpdateWindowData = JsonHelper.DeserializeFromFile(_titleUpdateJsonPath, SerializerContext.TitleUpdateMetadata); + TitleUpdateWindowData = JsonHelper.DeserializeFromFile(TitleUpdateJsonPath, _serializerContext.TitleUpdateMetadata); } catch { - Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}"); + Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}"); - _titleUpdateWindowData = new TitleUpdateMetadata + TitleUpdateWindowData = new TitleUpdateMetadata { Selected = "", - Paths = new List<string>() + Paths = new List<string>(), }; Save(); @@ -102,12 +100,12 @@ namespace Ryujinx.Ava.UI.ViewModels private void LoadUpdates() { - foreach (string path in _titleUpdateWindowData.Paths) + foreach (string path in TitleUpdateWindowData.Paths) { AddUpdate(path); } - TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null); + TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == TitleUpdateWindowData.Selected, null); SelectedUpdate = selected; @@ -126,7 +124,8 @@ namespace Ryujinx.Ava.UI.ViewModels { return -1; } - else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString())) + + if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString())) { return 1; } @@ -163,7 +162,7 @@ namespace Ryujinx.Ava.UI.ViewModels try { - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0); + (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0); if (controlNca != null && patchNca != null) { @@ -205,17 +204,17 @@ namespace Ryujinx.Ava.UI.ViewModels { OpenFileDialog dialog = new() { - Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle], - AllowMultiple = true + Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle], + AllowMultiple = true, }; dialog.Filters.Add(new FileDialogFilter { - Name = "NSP", - Extensions = { "nsp" } + Name = "NSP", + Extensions = { "nsp" }, }); - if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { string[] files = await dialog.ShowAsync(desktop.MainWindow); @@ -233,20 +232,20 @@ namespace Ryujinx.Ava.UI.ViewModels public void Save() { - _titleUpdateWindowData.Paths.Clear(); - _titleUpdateWindowData.Selected = ""; + TitleUpdateWindowData.Paths.Clear(); + TitleUpdateWindowData.Selected = ""; foreach (TitleUpdateModel update in TitleUpdates) { - _titleUpdateWindowData.Paths.Add(update.Path); + TitleUpdateWindowData.Paths.Add(update.Path); if (update == SelectedUpdate) { - _titleUpdateWindowData.Selected = update.Path; + TitleUpdateWindowData.Selected = update.Path; } } - JsonHelper.SerializeToFile(_titleUpdateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata); + JsonHelper.SerializeToFile(TitleUpdateJsonPath, TitleUpdateWindowData, _serializerContext.TitleUpdateMetadata); } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs index 558cad5a..cb8da9ed 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs @@ -28,7 +28,6 @@ namespace Ryujinx.Ava.UI.ViewModels private Color _backgroundColor = Colors.White; private int _selectedIndex; - private byte[] _selectedImage; public UserFirmwareAvatarSelectorViewModel() { @@ -78,11 +77,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public byte[] SelectedImage - { - get => _selectedImage; - private set => _selectedImage = value; - } + public byte[] SelectedImage { get; private set; } private void LoadImagesFromStore() { @@ -114,34 +109,32 @@ namespace Ryujinx.Ava.UI.ViewModels if (!string.IsNullOrWhiteSpace(avatarPath)) { - using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open)) - { - Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); - IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open); + + Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); + IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - foreach (DirectoryEntryEx item in romfs.EnumerateEntries()) + foreach (DirectoryEntryEx item in romfs.EnumerateEntries()) + { + // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy. + if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs")) { - // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy. - if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs")) - { - using var file = new UniqueRef<IFile>(); + using var 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(); + using MemoryStream stream = new(); + using MemoryStream streamPng = new(); - using (MemoryStream stream = new()) - using (MemoryStream streamPng = new()) - { - file.Get.AsStream().CopyTo(stream); + file.Get.AsStream().CopyTo(stream); - stream.Position = 0; + stream.Position = 0; - Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256); + Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256); - avatarImage.SaveAsPng(streamPng); + avatarImage.SaveAsPng(streamPng); - _avatarStore.Add(item.FullPath, streamPng.ToArray()); - } - } + _avatarStore.Add(item.FullPath, streamPng.ToArray()); } } } @@ -149,82 +142,81 @@ namespace Ryujinx.Ava.UI.ViewModels private static byte[] DecompressYaz0(Stream stream) { - using (BinaryReader reader = new(stream)) - { - reader.ReadInt32(); // Magic + using BinaryReader reader = new(stream); - uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32()); + reader.ReadInt32(); // Magic - reader.ReadInt64(); // Padding + uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32()); - byte[] input = new byte[stream.Length - stream.Position]; - stream.Read(input, 0, input.Length); + reader.ReadInt64(); // Padding - uint inputOffset = 0; + byte[] input = new byte[stream.Length - stream.Position]; + stream.Read(input, 0, input.Length); - byte[] output = new byte[decodedLength]; - uint outputOffset = 0; + uint inputOffset = 0; - ushort mask = 0; - byte header = 0; + byte[] output = new byte[decodedLength]; + uint outputOffset = 0; - while (outputOffset < decodedLength) + ushort mask = 0; + byte header = 0; + + while (outputOffset < decodedLength) + { + if ((mask >>= 1) == 0) { - if ((mask >>= 1) == 0) + header = input[inputOffset++]; + mask = 0x80; + } + + if ((header & mask) != 0) + { + if (outputOffset == output.Length) { - header = input[inputOffset++]; - mask = 0x80; + break; } - if ((header & mask) != 0) - { - if (outputOffset == output.Length) - { - break; - } + output[outputOffset++] = input[inputOffset++]; + } + else + { + byte byte1 = input[inputOffset++]; + byte byte2 = input[inputOffset++]; - output[outputOffset++] = input[inputOffset++]; + uint dist = (uint)((byte1 & 0xF) << 8) | byte2; + uint position = outputOffset - (dist + 1); + + uint length = (uint)byte1 >> 4; + if (length == 0) + { + length = (uint)input[inputOffset++] + 0x12; } else { - byte byte1 = input[inputOffset++]; - byte byte2 = input[inputOffset++]; - - uint dist = (uint)((byte1 & 0xF) << 8) | byte2; - uint position = outputOffset - (dist + 1); - - uint length = (uint)byte1 >> 4; - if (length == 0) - { - length = (uint)input[inputOffset++] + 0x12; - } - else - { - length += 2; - } - - uint gap = outputOffset - position; - uint nonOverlappingLength = length; - - if (nonOverlappingLength > gap) - { - nonOverlappingLength = gap; - } - - Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength); - outputOffset += nonOverlappingLength; - position += nonOverlappingLength; - length -= nonOverlappingLength; - - while (length-- > 0) - { - output[outputOffset++] = output[position++]; - } + length += 2; + } + + uint gap = outputOffset - position; + uint nonOverlappingLength = length; + + if (nonOverlappingLength > gap) + { + nonOverlappingLength = gap; } - } - return output; + Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength); + outputOffset += nonOverlappingLength; + position += nonOverlappingLength; + length -= nonOverlappingLength; + + while (length-- > 0) + { + output[outputOffset++] = output[position++]; + } + } } + + return output; } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs index 7261631c..8e7d41a5 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool FirmwareFound { get => _firmwareFound; - + set { _firmwareFound = value; @@ -15,4 +15,4 @@ namespace Ryujinx.Ava.UI.ViewModels } } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs index 8f997efc..70274847 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs @@ -1,7 +1,7 @@ using Microsoft.IdentityModel.Tokens; +using Ryujinx.Ava.UI.Models; using System; using System.Collections.ObjectModel; -using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; namespace Ryujinx.Ava.UI.ViewModels { @@ -20,6 +20,9 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsEmpty { get; set; } - public void Dispose() { } + public void Dispose() + { + GC.SuppressFinalize(this); + } } -}
\ No newline at end of file +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs index 097634a8..0a13f24a 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Ava.UI.ViewModels private string _search; private ObservableCollection<SaveModel> _saves = new(); private ObservableCollection<SaveModel> _views = new(); - private AccountManager _accountManager; + private readonly AccountManager _accountManager; public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId); @@ -102,19 +102,16 @@ namespace Ryujinx.Ava.UI.ViewModels private IComparer<SaveModel> GetComparer() { - switch (SortIndex) + return SortIndex switch { - case 0: - return OrderIndex == 0 - ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title) - : SortExpressionComparer<SaveModel>.Descending(save => save.Title); - case 1: - return OrderIndex == 0 - ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size) - : SortExpressionComparer<SaveModel>.Descending(save => save.Size); - default: - return null; - } + 0 => OrderIndex == 0 + ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title) + : SortExpressionComparer<SaveModel>.Descending(save => save.Title), + 1 => OrderIndex == 0 + ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size) + : SortExpressionComparer<SaveModel>.Descending(save => save.Size), + _ => null, + }; } } -}
\ No newline at end of file +} |
