diff options
| author | Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> | 2022-12-29 14:24:05 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-29 15:24:05 +0100 |
| commit | 76671d63d4f3ea18f8ad99e9ce9f0b2ec9a2599d (patch) | |
| tree | 05013214e4696a9254369d0706173f58877f6a83 /Ryujinx.Ava/Ui/ViewModels | |
| parent | 3d1a0bf3749afa14da5b5ba1e0666fdb78c99beb (diff) | |
Ava GUI: Restructure `Ryujinx.Ava` (#4165)
* Restructure `Ryujinx.Ava`
* Stylistic consistency
* Update Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Update Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
* Fix redundancies
* Remove redunancies
* Add back elses
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
Diffstat (limited to 'Ryujinx.Ava/Ui/ViewModels')
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/AmiiboWindowViewModel.cs | 451 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/AvatarProfileViewModel.cs | 363 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/BaseModel.cs | 15 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs | 900 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/MainWindowViewModel.cs | 1539 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs | 520 | ||||
| -rw-r--r-- | Ryujinx.Ava/Ui/ViewModels/UserProfileViewModel.cs | 213 |
7 files changed, 0 insertions, 4001 deletions
diff --git a/Ryujinx.Ava/Ui/ViewModels/AmiiboWindowViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/AmiiboWindowViewModel.cs deleted file mode 100644 index d007e0e7..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/AmiiboWindowViewModel.cs +++ /dev/null @@ -1,451 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Media.Imaging; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Models; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Utilities; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - public class AmiiboWindowViewModel : BaseModel, IDisposable - { - private const string DefaultJson = "{ \"amiibo\": [] }"; - private const float AmiiboImageSize = 350f; - - private readonly string _amiiboJsonPath; - private readonly byte[] _amiiboLogoBytes; - private readonly HttpClient _httpClient; - private readonly StyleableWindow _owner; - - private Bitmap _amiiboImage; - private List<Amiibo.AmiiboApi> _amiiboList; - private AvaloniaList<Amiibo.AmiiboApi> _amiibos; - private ObservableCollection<string> _amiiboSeries; - - private int _amiiboSelectedIndex; - private int _seriesSelectedIndex; - private bool _enableScanning; - private bool _showAllAmiibo; - private bool _useRandomUuid; - private string _usage; - - public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId) - { - _owner = owner; - _httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(5000) }; - LastScannedAmiiboId = lastScannedAmiiboId; - TitleId = titleId; - - Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo")); - - _amiiboJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json"); - _amiiboList = new List<Amiibo.AmiiboApi>(); - _amiiboSeries = new ObservableCollection<string>(); - _amiibos = new AvaloniaList<Amiibo.AmiiboApi>(); - - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png"); - - _ = LoadContentAsync(); - } - - public AmiiboWindowViewModel() { } - - public string TitleId { get; set; } - public string LastScannedAmiiboId { get; set; } - - public UserResult Response { get; private set; } - - public bool UseRandomUuid - { - get => _useRandomUuid; - set - { - _useRandomUuid = value; - - OnPropertyChanged(); - } - } - - public bool ShowAllAmiibo - { - get => _showAllAmiibo; - set - { - _showAllAmiibo = value; - -#pragma warning disable 4014 - ParseAmiiboData(); -#pragma warning restore 4014 - - OnPropertyChanged(); - } - } - - public AvaloniaList<Amiibo.AmiiboApi> AmiiboList - { - get => _amiibos; - set - { - _amiibos = value; - - OnPropertyChanged(); - } - } - - public ObservableCollection<string> AmiiboSeries - { - get => _amiiboSeries; - set - { - _amiiboSeries = value; - OnPropertyChanged(); - } - } - - public int SeriesSelectedIndex - { - get => _seriesSelectedIndex; - set - { - _seriesSelectedIndex = value; - - FilterAmiibo(); - - OnPropertyChanged(); - } - } - - public int AmiiboSelectedIndex - { - get => _amiiboSelectedIndex; - set - { - _amiiboSelectedIndex = value; - - EnableScanning = _amiiboSelectedIndex >= 0 && _amiiboSelectedIndex < _amiibos.Count; - - SetAmiiboDetails(); - - OnPropertyChanged(); - } - } - - public Bitmap AmiiboImage - { - get => _amiiboImage; - set - { - _amiiboImage = value; - - OnPropertyChanged(); - } - } - - public string Usage - { - get => _usage; - set - { - _usage = value; - - OnPropertyChanged(); - } - } - - public bool EnableScanning - { - get => _enableScanning; - set - { - _enableScanning = value; - - OnPropertyChanged(); - } - } - - public void Dispose() - { - _httpClient.Dispose(); - } - - private async Task LoadContentAsync() - { - string amiiboJsonString = DefaultJson; - - if (File.Exists(_amiiboJsonPath)) - { - amiiboJsonString = File.ReadAllText(_amiiboJsonPath); - - if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated)) - { - amiiboJsonString = await DownloadAmiiboJson(); - } - } - else - { - try - { - amiiboJsonString = await DownloadAmiiboJson(); - } - catch - { - ShowInfoDialog(); - } - } - - _amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo; - _amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList(); - - ParseAmiiboData(); - } - - private void ParseAmiiboData() - { - _amiiboSeries.Clear(); - _amiibos.Clear(); - - for (int i = 0; i < _amiiboList.Count; i++) - { - if (!_amiiboSeries.Contains(_amiiboList[i].AmiiboSeries)) - { - if (!ShowAllAmiibo) - { - foreach (Amiibo.AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch) - { - if (game != null) - { - if (game.GameId.Contains(TitleId)) - { - AmiiboSeries.Add(_amiiboList[i].AmiiboSeries); - - break; - } - } - } - } - else - { - AmiiboSeries.Add(_amiiboList[i].AmiiboSeries); - } - } - } - - if (LastScannedAmiiboId != "") - { - SelectLastScannedAmiibo(); - } - else - { - SeriesSelectedIndex = 0; - } - } - - private void SelectLastScannedAmiibo() - { - Amiibo.AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId); - - SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries); - AmiiboSelectedIndex = AmiiboList.IndexOf(scanned); - } - - private void FilterAmiibo() - { - _amiibos.Clear(); - - if (_seriesSelectedIndex < 0) - { - return; - } - - List<Amiibo.AmiiboApi> amiiboSortedList = _amiiboList - .Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex]) - .OrderBy(amiibo => amiibo.Name).ToList(); - - for (int i = 0; i < amiiboSortedList.Count; i++) - { - if (!_amiibos.Contains(amiiboSortedList[i])) - { - if (!_showAllAmiibo) - { - foreach (Amiibo.AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch) - { - if (game != null) - { - if (game.GameId.Contains(TitleId)) - { - _amiibos.Add(amiiboSortedList[i]); - - break; - } - } - } - } - else - { - _amiibos.Add(amiiboSortedList[i]); - } - } - } - - AmiiboSelectedIndex = 0; - } - - private void SetAmiiboDetails() - { - ResetAmiiboPreview(); - - Usage = string.Empty; - - if (_amiiboSelectedIndex < 0) - { - return; - } - - Amiibo.AmiiboApi selected = _amiibos[_amiiboSelectedIndex]; - - string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image; - - string usageString = ""; - - for (int i = 0; i < _amiiboList.Count; i++) - { - if (_amiiboList[i].Equals(selected)) - { - bool writable = false; - - foreach (Amiibo.AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch) - { - if (item.GameId.Contains(TitleId)) - { - foreach (Amiibo.AmiiboApiUsage usageItem in item.AmiiboUsage) - { - usageString += Environment.NewLine + - $"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"; - - writable = usageItem.Write; - } - } - } - - if (usageString.Length == 0) - { - usageString = LocaleManager.Instance["Unknown"] + "."; - } - - Usage = $"{LocaleManager.Instance["Usage"]} {(writable ? $" ({LocaleManager.Instance["Writable"]})" : "")} : {usageString}"; - } - } - - _ = UpdateAmiiboPreview(imageUrl); - } - - private async Task<bool> NeedsUpdate(DateTime oldLastModified) - { - try - { - HttpResponseMessage response = - await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); - - if (response.IsSuccessStatusCode) - { - return response.Content.Headers.LastModified != oldLastModified; - } - - return false; - } - catch - { - ShowInfoDialog(); - - return false; - } - } - - private async Task<string> DownloadAmiiboJson() - { - HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - - if (response.IsSuccessStatusCode) - { - string amiiboJsonString = await response.Content.ReadAsStringAsync(); - - using (FileStream amiiboJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough)) - { - amiiboJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); - } - - return amiiboJsonString; - } - - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"], - LocaleManager.Instance["DialogAmiiboApiFailFetchMessage"], - LocaleManager.Instance["InputDialogOk"], - "", - LocaleManager.Instance["RyujinxInfo"]); - - Close(); - - return DefaultJson; - } - - private void Close() - { - Dispatcher.UIThread.Post(_owner.Close); - } - - private async Task UpdateAmiiboPreview(string imageUrl) - { - HttpResponseMessage response = await _httpClient.GetAsync(imageUrl); - - if (response.IsSuccessStatusCode) - { - byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); - using (MemoryStream memoryStream = new(amiiboPreviewBytes)) - { - Bitmap bitmap = new(memoryStream); - - 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); - - AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight)); - } - } - } - - private void ResetAmiiboPreview() - { - using (MemoryStream memoryStream = new(_amiiboLogoBytes)) - { - Bitmap bitmap = new(memoryStream); - - AmiiboImage = bitmap; - } - } - - private async void ShowInfoDialog() - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"], - LocaleManager.Instance["DialogAmiiboApiConnectErrorMessage"], - LocaleManager.Instance["InputDialogOk"], - "", - LocaleManager.Instance["RyujinxInfo"]); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Ava/Ui/ViewModels/AvatarProfileViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/AvatarProfileViewModel.cs deleted file mode 100644 index c2983741..00000000 --- a/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/Ryujinx.Ava/Ui/ViewModels/BaseModel.cs b/Ryujinx.Ava/Ui/ViewModels/BaseModel.cs deleted file mode 100644 index abb14c7d..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/BaseModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - public class BaseModel : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs deleted file mode 100644 index c7690316..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs +++ /dev/null @@ -1,900 +0,0 @@ -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Svg.Skia; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Models; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Configuration.Hid.Controller.Motion; -using Ryujinx.Common.Configuration.Hid.Keyboard; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.Input; -using Ryujinx.Ui.Common.Configuration; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Text.Json; -using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; -using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; -using Key = Ryujinx.Common.Configuration.Hid.Key; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - public class ControllerSettingsViewModel : BaseModel, IDisposable - { - private const string Disabled = "disabled"; - private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg"; - private const string JoyConPairResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg"; - private const string JoyConLeftResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg"; - private const string JoyConRightResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg"; - private const string KeyboardString = "keyboard"; - private const string ControllerString = "controller"; - private readonly MainWindow _mainWindow; - - private PlayerIndex _playerId; - private int _controller; - private int _controllerNumber = 0; - private string _controllerImage; - private int _device; - private object _configuration; - private string _profileName; - private bool _isLoaded; - private readonly UserControl _owner; - - public IGamepadDriver AvaloniaKeyboardDriver { get; } - public IGamepad SelectedGamepad { get; private set; } - - public ObservableCollection<PlayerModel> PlayerIndexes { get; set; } - public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; } - internal ObservableCollection<ControllerModel> Controllers { get; set; } - public AvaloniaList<string> ProfilesList { get; set; } - public AvaloniaList<string> DeviceList { get; set; } - - // XAML Flags - public bool ShowSettings => _device > 0; - public bool IsController => _device > 1; - public bool IsKeyboard => !IsController; - public bool IsRight { get; set; } - public bool IsLeft { get; set; } - - public bool IsModified { get; set; } - - public object Configuration - { - get => _configuration; - set - { - _configuration = value; - - OnPropertyChanged(); - } - } - - public PlayerIndex PlayerId - { - get => _playerId; - set - { - if (IsModified) - { - return; - } - - IsModified = false; - _playerId = value; - - if (!Enum.IsDefined(typeof(PlayerIndex), _playerId)) - { - _playerId = PlayerIndex.Player1; - } - - LoadConfiguration(); - LoadDevice(); - LoadProfiles(); - - _isLoaded = true; - - OnPropertyChanged(); - } - } - - public int Controller - { - get => _controller; - set - { - _controller = value; - - if (_controller == -1) - { - _controller = 0; - } - - if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1) - { - ControllerType controller = Controllers[_controller].Type; - - IsLeft = true; - IsRight = true; - - switch (controller) - { - case ControllerType.Handheld: - ControllerImage = JoyConPairResource; - break; - case ControllerType.ProController: - ControllerImage = ProControllerResource; - break; - case ControllerType.JoyconPair: - ControllerImage = JoyConPairResource; - break; - case ControllerType.JoyconLeft: - ControllerImage = JoyConLeftResource; - IsRight = false; - break; - case ControllerType.JoyconRight: - ControllerImage = JoyConRightResource; - IsLeft = false; - break; - } - - LoadInputDriver(); - LoadProfiles(); - } - - OnPropertyChanged(); - NotifyChanges(); - } - } - - public string ControllerImage - { - get => _controllerImage; - set - { - _controllerImage = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(Image)); - } - } - - public SvgImage Image - { - get - { - SvgImage image = new SvgImage(); - - if (!string.IsNullOrWhiteSpace(_controllerImage)) - { - SvgSource source = new SvgSource(); - - source.Load(EmbeddedResources.GetStream(_controllerImage)); - - image.Source = source; - } - - return image; - } - } - - public string ProfileName - { - get => _profileName; set - { - _profileName = value; - - OnPropertyChanged(); - } - } - - public int Device - { - get => _device; - set - { - _device = value < 0 ? 0 : value; - - if (_device >= Devices.Count) - { - return; - } - - var selected = Devices[_device].Type; - - if (selected != DeviceType.None) - { - LoadControllers(); - - if (_isLoaded) - { - LoadConfiguration(LoadDefaultConfiguration()); - } - } - - OnPropertyChanged(); - NotifyChanges(); - } - } - - public InputConfig Config { get; set; } - - public ControllerSettingsViewModel(UserControl owner) : this() - { - _owner = owner; - - if (Program.PreviewerDetached) - { - _mainWindow = - (MainWindow)((IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current - .ApplicationLifetime).MainWindow; - - AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); - - _mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; - _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; - if (_mainWindow.AppHost != null) - { - _mainWindow.AppHost.NpadManager.BlockInputUpdates(); - } - - _isLoaded = false; - - LoadDevices(); - - PlayerId = PlayerIndex.Player1; - } - } - - public ControllerSettingsViewModel() - { - PlayerIndexes = new ObservableCollection<PlayerModel>(); - Controllers = new ObservableCollection<ControllerModel>(); - Devices = new ObservableCollection<(DeviceType Type, string Id, string Name)>(); - ProfilesList = new AvaloniaList<string>(); - DeviceList = new AvaloniaList<string>(); - - ControllerImage = ProControllerResource; - - PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance["ControllerSettingsPlayer1"])); - PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance["ControllerSettingsPlayer2"])); - PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance["ControllerSettingsPlayer3"])); - PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance["ControllerSettingsPlayer4"])); - PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance["ControllerSettingsPlayer5"])); - PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance["ControllerSettingsPlayer6"])); - PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance["ControllerSettingsPlayer7"])); - PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance["ControllerSettingsPlayer8"])); - PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance["ControllerSettingsHandheld"])); - } - - private void LoadConfiguration(InputConfig inputConfig = null) - { - Config = inputConfig ?? ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerId); - - if (Config is StandardKeyboardInputConfig keyboardInputConfig) - { - Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig); - } - - if (Config is StandardControllerInputConfig controllerInputConfig) - { - Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig); - } - } - - public void LoadDevice() - { - if (Config == null || Config.Backend == InputBackendType.Invalid) - { - Device = 0; - } - else - { - var type = DeviceType.None; - - if (Config is StandardKeyboardInputConfig) - { - type = DeviceType.Keyboard; - } - - if (Config is StandardControllerInputConfig) - { - type = DeviceType.Controller; - } - - var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id); - if (item != default) - { - Device = Devices.ToList().FindIndex(x => x.Id == item.Id); - } - else - { - Device = 0; - } - } - } - - public async void ShowMotionConfig() - { - await MotionSettingsWindow.Show(this); - } - - public async void ShowRumbleConfig() - { - await RumbleSettingsWindow.Show(this); - } - - private void LoadInputDriver() - { - if (_device < 0) - { - return; - } - - string id = GetCurrentGamepadId(); - var type = Devices[Device].Type; - - if (type == DeviceType.None) - { - return; - } - else if (type == DeviceType.Keyboard) - { - if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver) - { - // NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused... - SelectedGamepad = AvaloniaKeyboardDriver.GetGamepad(id); - } - else - { - SelectedGamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id); - } - } - else - { - SelectedGamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id); - } - } - - private void HandleOnGamepadDisconnected(string id) - { - Dispatcher.UIThread.Post(() => - { - LoadDevices(); - }); - } - - private void HandleOnGamepadConnected(string id) - { - Dispatcher.UIThread.Post(() => - { - LoadDevices(); - }); - } - - private string GetCurrentGamepadId() - { - if (_device < 0) - { - return string.Empty; - } - - var device = Devices[Device]; - - if (device.Type == DeviceType.None) - { - return null; - } - - return device.Id.Split(" ")[0]; - } - - public void LoadControllers() - { - Controllers.Clear(); - - if (_playerId == PlayerIndex.Handheld) - { - Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance["ControllerSettingsControllerTypeHandheld"])); - - Controller = 0; - } - else - { - Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance["ControllerSettingsControllerTypeProController"])); - Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConPair"])); - Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConLeft"])); - Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConRight"])); - - if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1) - { - Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType); - } - else - { - Controller = 0; - } - } - } - - private static string GetShortGamepadName(string str) - { - const string Ellipsis = "..."; - const int MaxSize = 50; - - if (str.Length > MaxSize) - { - return str.Substring(0, MaxSize - Ellipsis.Length) + Ellipsis; - } - - return str; - } - - private static string GetShortGamepadId(string str) - { - const string Hyphen = "-"; - const int Offset = 1; - - return str.Substring(str.IndexOf(Hyphen) + Offset); - } - - public void LoadDevices() - { - lock (Devices) - { - Devices.Clear(); - DeviceList.Clear(); - Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance["ControllerSettingsDeviceDisabled"])); - - foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds) - { - using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id); - - if (gamepad != null) - { - Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}")); - } - } - - foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds) - { - using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id); - - if (gamepad != null) - { - if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id))) - { - _controllerNumber++; - } - - Devices.Add((DeviceType.Controller, id, $"{GetShortGamepadName(gamepad.Name)} ({_controllerNumber})")); - } - } - - _controllerNumber = 0; - - DeviceList.AddRange(Devices.Select(x => x.Name)); - Device = Math.Min(Device, DeviceList.Count); - } - } - - private string GetProfileBasePath() - { - string path = AppDataManager.ProfilesDirPath; - var type = Devices[Device == -1 ? 0 : Device].Type; - - if (type == DeviceType.Keyboard) - { - path = Path.Combine(path, KeyboardString); - } - else if (type == DeviceType.Controller) - { - path = Path.Combine(path, ControllerString); - } - - return path; - } - - private void LoadProfiles() - { - ProfilesList.Clear(); - - string basePath = GetProfileBasePath(); - - if (!Directory.Exists(basePath)) - { - Directory.CreateDirectory(basePath); - } - - ProfilesList.Add((LocaleManager.Instance["ControllerSettingsProfileDefault"])); - - foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories)) - { - ProfilesList.Add(Path.GetFileNameWithoutExtension(profile)); - } - - if (string.IsNullOrWhiteSpace(ProfileName)) - { - ProfileName = LocaleManager.Instance["ControllerSettingsProfileDefault"]; - } - } - - public InputConfig LoadDefaultConfiguration() - { - var activeDevice = Devices.FirstOrDefault(); - - if (Devices.Count > 0 && Device < Devices.Count && Device >= 0) - { - activeDevice = Devices[Device]; - } - - InputConfig config; - if (activeDevice.Type == DeviceType.Keyboard) - { - string id = activeDevice.Id; - - config = new StandardKeyboardInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.WindowKeyboard, - Id = id, - ControllerType = ControllerType.ProController, - LeftJoycon = new LeftJoyconCommonConfig<Key> - { - DpadUp = Key.Up, - DpadDown = Key.Down, - DpadLeft = Key.Left, - DpadRight = Key.Right, - ButtonMinus = Key.Minus, - ButtonL = Key.E, - ButtonZl = Key.Q, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound - }, - LeftJoyconStick = - new JoyconConfigKeyboardStick<Key> - { - StickUp = Key.W, - StickDown = Key.S, - StickLeft = Key.A, - StickRight = Key.D, - StickButton = Key.F - }, - RightJoycon = new RightJoyconCommonConfig<Key> - { - ButtonA = Key.Z, - ButtonB = Key.X, - ButtonX = Key.C, - ButtonY = Key.V, - ButtonPlus = Key.Plus, - ButtonR = Key.U, - ButtonZr = Key.O, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound - }, - RightJoyconStick = new JoyconConfigKeyboardStick<Key> - { - StickUp = Key.I, - StickDown = Key.K, - StickLeft = Key.J, - StickRight = Key.L, - StickButton = Key.H - } - }; - } - else if (activeDevice.Type == DeviceType.Controller) - { - bool isNintendoStyle = Devices.ToList().Find(x => x.Id == activeDevice.Id).Name.Contains("Nintendo"); - - string id = activeDevice.Id.Split(" ")[0]; - - config = new StandardControllerInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.GamepadSDL2, - Id = id, - ControllerType = ControllerType.ProController, - DeadzoneLeft = 0.1f, - DeadzoneRight = 0.1f, - RangeLeft = 1.0f, - RangeRight = 1.0f, - TriggerThreshold = 0.5f, - LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId> - { - DpadUp = ConfigGamepadInputId.DpadUp, - DpadDown = ConfigGamepadInputId.DpadDown, - DpadLeft = ConfigGamepadInputId.DpadLeft, - DpadRight = ConfigGamepadInputId.DpadRight, - ButtonMinus = ConfigGamepadInputId.Minus, - ButtonL = ConfigGamepadInputId.LeftShoulder, - ButtonZl = ConfigGamepadInputId.LeftTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound - }, - LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> - { - Joystick = ConfigStickInputId.Left, - StickButton = ConfigGamepadInputId.LeftStick, - InvertStickX = false, - InvertStickY = false - }, - RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId> - { - ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B, - ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A, - ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y, - ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X, - ButtonPlus = ConfigGamepadInputId.Plus, - ButtonR = ConfigGamepadInputId.RightShoulder, - ButtonZr = ConfigGamepadInputId.RightTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound - }, - RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> - { - Joystick = ConfigStickInputId.Right, - StickButton = ConfigGamepadInputId.RightStick, - InvertStickX = false, - InvertStickY = false - }, - Motion = new StandardMotionConfigController - { - MotionBackend = MotionInputBackendType.GamepadDriver, - EnableMotion = true, - Sensitivity = 100, - GyroDeadzone = 1 - }, - Rumble = new RumbleConfigController - { - StrongRumble = 1f, - WeakRumble = 1f, - EnableRumble = false - } - }; - } - else - { - config = new InputConfig(); - } - - config.PlayerIndex = _playerId; - - return config; - } - - public async void LoadProfile() - { - if (Device == 0) - { - return; - } - - InputConfig config = null; - - if (string.IsNullOrWhiteSpace(ProfileName)) - { - return; - } - - if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"]) - { - config = LoadDefaultConfiguration(); - } - else - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - if (!File.Exists(path)) - { - var index = ProfilesList.IndexOf(ProfileName); - if (index != -1) - { - ProfilesList.RemoveAt(index); - } - return; - } - - try - { - using (Stream stream = File.OpenRead(path)) - { - config = JsonHelper.Deserialize<InputConfig>(stream); - } - } - catch (JsonException) { } - catch (InvalidOperationException) - { - Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system."); - - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogProfileInvalidProfileErrorMessage"], ProfileName)); - - return; - } - } - - if (config != null) - { - _isLoaded = false; - - LoadConfiguration(config); - - LoadDevice(); - - _isLoaded = true; - - NotifyChanges(); - } - } - - public async void SaveProfile() - { - if (Device == 0) - { - return; - } - - if (Configuration == null) - { - return; - } - - if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"]) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileDefaultProfileOverwriteErrorMessage"]); - - return; - } - else - { - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - InputConfig config = null; - - 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, true); - - await File.WriteAllTextAsync(path, jsonString); - - LoadProfiles(); - } - else - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileInvalidProfileNameErrorMessage"]); - } - } - } - - public async void RemoveProfile() - { - if (Device == 0 || ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"] || ProfilesList.IndexOf(ProfileName) == -1) - { - return; - } - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance["DialogProfileDeleteProfileTitle"], - LocaleManager.Instance["DialogProfileDeleteProfileMessage"], - LocaleManager.Instance["InputDialogYes"], - LocaleManager.Instance["InputDialogNo"], - LocaleManager.Instance["RyujinxConfirm"]); - - if (result == UserResult.Yes) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - if (File.Exists(path)) - { - File.Delete(path); - } - - LoadProfiles(); - } - } - - public void Save() - { - IsModified = false; - - List<InputConfig> newConfig = new(); - - newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value); - - newConfig.Remove(newConfig.Find(x => x == null)); - - if (Device == 0) - { - newConfig.Remove(newConfig.Find(x => x.PlayerIndex == this.PlayerId)); - } - else - { - var device = Devices[Device]; - - if (device.Type == DeviceType.Keyboard) - { - var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>; - inputConfig.Id = device.Id; - } - else - { - var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>; - inputConfig.Id = device.Id.Split(" ")[0]; - } - - var config = !IsController - ? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig() - : (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig(); - config.ControllerType = Controllers[_controller].Type; - config.PlayerIndex = _playerId; - - int i = newConfig.FindIndex(x => x.PlayerIndex == PlayerId); - if (i == -1) - { - newConfig.Add(config); - } - else - { - newConfig[i] = config; - } - } - - _mainWindow.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse); - - // Atomically replace and signal input change. - // NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event. - ConfigurationState.Instance.Hid.InputConfig.Value = newConfig; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - - public void NotifyChange(string property) - { - OnPropertyChanged(property); - } - - public void NotifyChanges() - { - OnPropertyChanged(nameof(Configuration)); - OnPropertyChanged(nameof(IsController)); - OnPropertyChanged(nameof(ShowSettings)); - OnPropertyChanged(nameof(IsKeyboard)); - OnPropertyChanged(nameof(IsRight)); - OnPropertyChanged(nameof(IsLeft)); - } - - public void Dispose() - { - _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; - _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; - - _mainWindow.AppHost?.NpadManager.UnblockInputUpdates(); - - SelectedGamepad?.Dispose(); - - AvaloniaKeyboardDriver.Dispose(); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Ava/Ui/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/MainWindowViewModel.cs deleted file mode 100644 index 06513e37..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/MainWindowViewModel.cs +++ /dev/null @@ -1,1539 +0,0 @@ -using ARMeilleure.Translation.PTC; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Media; -using Avalonia.Threading; -using DynamicData; -using DynamicData.Binding; -using LibHac.Fs; -using LibHac.FsSystem; -using LibHac.Ncm; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.HLE; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; -using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Path = System.IO.Path; -using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - internal class MainWindowViewModel : BaseModel - { - private const int HotKeyPressDelayMs = 500; - - private readonly MainWindow _owner; - private ObservableCollection<ApplicationData> _applications; - private string _aspectStatusText; - - private string _loadHeading; - private string _cacheLoadStatus; - private string _searchText; - private Timer _searchTimer; - private string _dockedStatusText; - private string _fifoStatusText; - private string _gameStatusText; - private string _volumeStatusText; - private string _gpuStatusText; - private bool _isAmiiboRequested; - private bool _isGameRunning; - private bool _isLoading; - private int _progressMaximum; - private int _progressValue; - private long _lastFullscreenToggle = Environment.TickCount64; - private bool _showLoadProgress; - private bool _showMenuAndStatusBar = true; - private bool _showStatusSeparator; - private Brush _progressBarForegroundColor; - private Brush _progressBarBackgroundColor; - private Brush _vsyncColor; - private byte[] _selectedIcon; - private bool _isAppletMenuActive; - private int _statusBarProgressMaximum; - private int _statusBarProgressValue; - private bool _isPaused; - private bool _showContent = true; - private bool _isLoadingIndeterminate = true; - private bool _showAll; - private string _lastScannedAmiiboId; - private ReadOnlyObservableCollection<ApplicationData> _appsObservableList; - public ApplicationLibrary ApplicationLibrary => _owner.ApplicationLibrary; - - public string TitleName { get; internal set; } - - public MainWindowViewModel(MainWindow owner) : this() - { - _owner = owner; - } - - public MainWindowViewModel() - { - Applications = new ObservableCollection<ApplicationData>(); - - Applications.ToObservableChangeSet() - .Filter(Filter) - .Sort(GetComparer()) - .Bind(out _appsObservableList).AsObservableList(); - - if (Program.PreviewerDetached) - { - LoadConfigurableHotKeys(); - - Volume = ConfigurationState.Instance.System.AudioVolume; - } - } - - public void Initialize() - { - ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated; - ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded; - - Ptc.PtcStateChanged -= ProgressHandler; - Ptc.PtcStateChanged += ProgressHandler; - } - - public string SearchText - { - get => _searchText; - set - { - _searchText = value; - - _searchTimer?.Dispose(); - - _searchTimer = new Timer(TimerCallback, null, 1000, 0); - } - } - - private void TimerCallback(object obj) - { - RefreshView(); - - _searchTimer.Dispose(); - _searchTimer = null; - } - - public ReadOnlyObservableCollection<ApplicationData> AppsObservableList - { - get => _appsObservableList; - set - { - _appsObservableList = value; - - OnPropertyChanged(); - } - } - - public bool IsPaused - { - get => _isPaused; - set - { - _isPaused = value; - - OnPropertyChanged(); - } - } - - public bool EnableNonGameRunningControls => !IsGameRunning; - - public bool ShowFirmwareStatus => !ShowLoadProgress; - - public bool IsGameRunning - { - get => _isGameRunning; - set - { - _isGameRunning = value; - - if (!value) - { - ShowMenuAndStatusBar = false; - } - - OnPropertyChanged(); - OnPropertyChanged(nameof(EnableNonGameRunningControls)); - OnPropertyChanged(nameof(ShowFirmwareStatus)); - } - } - - public bool IsAmiiboRequested - { - get => _isAmiiboRequested && _isGameRunning; - set - { - _isAmiiboRequested = value; - - OnPropertyChanged(); - } - } - - public bool ShowLoadProgress - { - get => _showLoadProgress; - set - { - _showLoadProgress = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(ShowFirmwareStatus)); - } - } - - public string GameStatusText - { - get => _gameStatusText; - set - { - _gameStatusText = value; - - OnPropertyChanged(); - } - } - - private string _showUikey = "F4"; - private string _pauseKey = "F5"; - private string _screenshotkey = "F8"; - private float _volume; - private string _backendText; - - public ApplicationData SelectedApplication - { - get - { - return Glyph switch - { - Glyph.List => _owner.GameList.SelectedApplication, - Glyph.Grid => _owner.GameGrid.SelectedApplication, - _ => null, - }; - } - } - - public string LoadHeading - { - get => _loadHeading; - set - { - _loadHeading = value; - - OnPropertyChanged(); - } - } - - public string CacheLoadStatus - { - get => _cacheLoadStatus; - set - { - _cacheLoadStatus = value; - - OnPropertyChanged(); - } - } - - public Brush ProgressBarBackgroundColor - { - get => _progressBarBackgroundColor; - set - { - _progressBarBackgroundColor = value; - - OnPropertyChanged(); - } - } - - public Brush ProgressBarForegroundColor - { - get => _progressBarForegroundColor; - set - { - _progressBarForegroundColor = value; - - OnPropertyChanged(); - } - } - - public Brush VsyncColor - { - get => _vsyncColor; - set - { - _vsyncColor = value; - - OnPropertyChanged(); - } - } - - public byte[] SelectedIcon - { - get => _selectedIcon; - set - { - _selectedIcon = value; - - OnPropertyChanged(); - } - } - - public int ProgressMaximum - { - get => _progressMaximum; - set - { - _progressMaximum = value; - - OnPropertyChanged(); - } - } - - public int ProgressValue - { - get => _progressValue; - set - { - _progressValue = value; - - OnPropertyChanged(); - } - } - - public int StatusBarProgressMaximum - { - get => _statusBarProgressMaximum; - set - { - _statusBarProgressMaximum = value; - - OnPropertyChanged(); - } - } - - public int StatusBarProgressValue - { - get => _statusBarProgressValue; - set - { - _statusBarProgressValue = value; - - OnPropertyChanged(); - } - } - - public string FifoStatusText - { - get => _fifoStatusText; - set - { - _fifoStatusText = value; - - OnPropertyChanged(); - } - } - - public string GpuNameText - { - get => _gpuStatusText; - set - { - _gpuStatusText = value; - - OnPropertyChanged(); - } - } - - public string BackendText - { - get => _backendText; - set - { - _backendText = value; - - OnPropertyChanged(); - } - } - - public string DockedStatusText - { - get => _dockedStatusText; - set - { - _dockedStatusText = value; - - OnPropertyChanged(); - } - } - - public string AspectRatioStatusText - { - get => _aspectStatusText; - set - { - _aspectStatusText = value; - - OnPropertyChanged(); - } - } - - public string VolumeStatusText - { - get => _volumeStatusText; - set - { - _volumeStatusText = value; - - OnPropertyChanged(); - } - } - - public bool VolumeMuted => _volume == 0; - - public float Volume - { - get => _volume; - set - { - _volume = value; - - if (_isGameRunning) - { - _owner.AppHost.Device.SetVolume(_volume); - } - - OnPropertyChanged(nameof(VolumeStatusText)); - OnPropertyChanged(nameof(VolumeMuted)); - OnPropertyChanged(); - } - } - - public bool ShowStatusSeparator - { - get => _showStatusSeparator; - set - { - _showStatusSeparator = value; - - OnPropertyChanged(); - } - } - - public bool ShowMenuAndStatusBar - { - get => _showMenuAndStatusBar; - set - { - _showMenuAndStatusBar = value; - - OnPropertyChanged(); - } - } - - public bool IsLoadingIndeterminate - { - get => _isLoadingIndeterminate; - set - { - _isLoadingIndeterminate = value; - - OnPropertyChanged(); - } - } - - public bool ShowContent - { - get => _showContent; - set - { - _showContent = value; - - OnPropertyChanged(); - } - } - - public bool IsAppletMenuActive - { - get => _isAppletMenuActive && EnableNonGameRunningControls; - set - { - _isAppletMenuActive = value; - - OnPropertyChanged(); - } - } - - public bool IsGrid => Glyph == Glyph.Grid; - public bool IsList => Glyph == Glyph.List; - - internal void Sort(bool isAscending) - { - IsAscending = isAscending; - - RefreshView(); - } - - internal void Sort(ApplicationSort sort) - { - SortMode = sort; - - RefreshView(); - } - - private IComparer<ApplicationData> GetComparer() - { - return SortMode switch - { - ApplicationSort.LastPlayed => new Models.Generic.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) - : SortExpressionComparer<ApplicationData>.Descending(app => app.TimePlayedNum), - ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName) - : SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName), - ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite), - ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Developer), - ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) - : SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension), - ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Path), - _ => null, - }; - } - - private void RefreshView() - { - RefreshGrid(); - } - - private void RefreshGrid() - { - Applications.ToObservableChangeSet() - .Filter(Filter) - .Sort(GetComparer()) - .Bind(out _appsObservableList).AsObservableList(); - - OnPropertyChanged(nameof(AppsObservableList)); - } - - public bool StartGamesInFullscreen - { - get => ConfigurationState.Instance.Ui.StartFullscreen; - set - { - ConfigurationState.Instance.Ui.StartFullscreen.Value = value; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - OnPropertyChanged(); - } - } - - public bool ShowConsole - { - get => ConfigurationState.Instance.Ui.ShowConsole; - set - { - ConfigurationState.Instance.Ui.ShowConsole.Value = value; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - OnPropertyChanged(); - } - } - - public bool ShowConsoleVisible - { - get => ConsoleHelper.SetConsoleWindowStateSupported; - } - - public ObservableCollection<ApplicationData> Applications - { - get => _applications; - set - { - _applications = value; - - OnPropertyChanged(); - } - } - - public Glyph Glyph - { - get => (Glyph)ConfigurationState.Instance.Ui.GameListViewMode.Value; - set - { - ConfigurationState.Instance.Ui.GameListViewMode.Value = (int)value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(IsGrid)); - OnPropertyChanged(nameof(IsList)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public bool ShowNames - { - get => ConfigurationState.Instance.Ui.ShowNames && ConfigurationState.Instance.Ui.GridSize > 1; set - { - ConfigurationState.Instance.Ui.ShowNames.Value = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(GridSizeScale)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - internal ApplicationSort SortMode - { - get => (ApplicationSort)ConfigurationState.Instance.Ui.ApplicationSort.Value; - private set - { - ConfigurationState.Instance.Ui.ApplicationSort.Value = (int)value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(SortName)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite; - public bool IsSortedByTitle => SortMode == ApplicationSort.Title; - public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer; - public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed; - public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed; - public bool IsSortedByType => SortMode == ApplicationSort.FileType; - public bool IsSortedBySize => SortMode == ApplicationSort.FileSize; - public bool IsSortedByPath => SortMode == ApplicationSort.Path; - - public string SortName - { - get - { - return SortMode switch - { - ApplicationSort.Title => LocaleManager.Instance["GameListHeaderApplication"], - ApplicationSort.Developer => LocaleManager.Instance["GameListHeaderDeveloper"], - ApplicationSort.LastPlayed => LocaleManager.Instance["GameListHeaderLastPlayed"], - ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"], - ApplicationSort.FileType => LocaleManager.Instance["GameListHeaderFileExtension"], - ApplicationSort.FileSize => LocaleManager.Instance["GameListHeaderFileSize"], - ApplicationSort.Path => LocaleManager.Instance["GameListHeaderPath"], - ApplicationSort.Favorite => LocaleManager.Instance["CommonFavorite"], - _ => string.Empty, - }; - } - } - - public bool IsAscending - { - get => ConfigurationState.Instance.Ui.IsAscendingOrder; - private set - { - ConfigurationState.Instance.Ui.IsAscendingOrder.Value = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(SortMode)); - OnPropertyChanged(nameof(SortName)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public KeyGesture ShowUiKey - { - get => KeyGesture.Parse(_showUikey); set - { - _showUikey = value.ToString(); - - OnPropertyChanged(); - } - } - - public KeyGesture ScreenshotKey - { - get => KeyGesture.Parse(_screenshotkey); set - { - _screenshotkey = value.ToString(); - - OnPropertyChanged(); - } - } - - public KeyGesture PauseKey - { - get => KeyGesture.Parse(_pauseKey); set - { - _pauseKey = value.ToString(); - - OnPropertyChanged(); - } - } - - public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1; - public bool IsGridMedium => ConfigurationState.Instance.Ui.GridSize == 2; - public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3; - public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4; - - public int GridSizeScale - { - get => ConfigurationState.Instance.Ui.GridSize; - set - { - ConfigurationState.Instance.Ui.GridSize.Value = value; - - if (value < 2) - { - ShowNames = false; - } - - OnPropertyChanged(); - OnPropertyChanged(nameof(IsGridSmall)); - OnPropertyChanged(nameof(IsGridMedium)); - OnPropertyChanged(nameof(IsGridLarge)); - OnPropertyChanged(nameof(IsGridHuge)); - OnPropertyChanged(nameof(ShowNames)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public async void OpenAmiiboWindow() - { - if (!_isAmiiboRequested) - { - return; - } - - if (_owner.AppHost.Device.System.SearchingForAmiibo(out int deviceId)) - { - string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper(); - AmiiboWindow window = new(_showAll, _lastScannedAmiiboId, titleId); - - await window.ShowDialog(_owner); - - if (window.IsScanned) - { - _showAll = window.ViewModel.ShowAllAmiibo; - _lastScannedAmiiboId = window.ScannedAmiibo.GetId(); - - _owner.AppHost.Device.System.ScanAmiibo(deviceId, _lastScannedAmiiboId, window.ViewModel.UseRandomUuid); - } - } - } - - public void HandleShaderProgress(Switch emulationContext) - { - emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler; - emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler; - } - - private bool Filter(object arg) - { - if (arg is ApplicationData app) - { - return string.IsNullOrWhiteSpace(_searchText) || app.TitleName.ToLower().Contains(_searchText.ToLower()); - } - - return false; - } - - private void ApplicationLibrary_ApplicationAdded(object sender, ApplicationAddedEventArgs e) - { - AddApplication(e.AppData); - } - - private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e) - { - StatusBarProgressValue = e.NumAppsLoaded; - StatusBarProgressMaximum = e.NumAppsFound; - - LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum); - - Dispatcher.UIThread.Post(() => - { - if (e.NumAppsFound == 0) - { - _owner.LoadProgressBar.IsVisible = false; - } - - if (e.NumAppsLoaded == e.NumAppsFound) - { - _owner.LoadProgressBar.IsVisible = false; - } - }); - } - - public void AddApplication(ApplicationData applicationData) - { - Dispatcher.UIThread.InvokeAsync(() => - { - Applications.Add(applicationData); - }); - } - - public async void LoadApplications() - { - await Dispatcher.UIThread.InvokeAsync(() => - { - Applications.Clear(); - - _owner.LoadProgressBar.IsVisible = true; - StatusBarProgressMaximum = 0; - StatusBarProgressValue = 0; - - LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0); - }); - - ReloadGameList(); - } - - private void ReloadGameList() - { - if (_isLoading) - { - return; - } - - _isLoading = true; - - Thread thread = new(() => - { - ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language); - - _isLoading = false; - }) - { Name = "GUI.AppListLoadThread", Priority = ThreadPriority.AboveNormal }; - - thread.Start(); - } - - public async void OpenFile() - { - OpenFileDialog dialog = new() - { - Title = LocaleManager.Instance["OpenFileDialogTitle"] - }; - - dialog.Filters.Add(new FileDialogFilter - { - Name = LocaleManager.Instance["AllSupportedFormats"], - Extensions = - { - "nsp", - "pfs0", - "xci", - "nca", - "nro", - "nso" - } - }); - - 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" } }); - - string[] files = await dialog.ShowAsync(_owner); - - if (files != null && files.Length > 0) - { - _owner.LoadApplication(files[0]); - } - } - - public async void OpenFolder() - { - OpenFolderDialog dialog = new() - { - Title = LocaleManager.Instance["OpenFolderDialogTitle"] - }; - - string folder = await dialog.ShowAsync(_owner); - - if (!string.IsNullOrWhiteSpace(folder) && Directory.Exists(folder)) - { - _owner.LoadApplication(folder); - } - } - - public void LoadConfigurableHotKeys() - { - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) - { - ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None); - } - - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) - { - ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None); - } - - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) - { - PauseKey = new KeyGesture(pauseKey, KeyModifiers.None); - } - } - - public void TakeScreenshot() - { - _owner.AppHost.ScreenshotRequested = true; - } - - public void HideUi() - { - ShowMenuAndStatusBar = false; - } - - public void SetListMode() - { - Glyph = Glyph.List; - } - - public void SetGridMode() - { - Glyph = Glyph.Grid; - } - - public void OpenMiiApplet() - { - string contentPath = _owner.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program); - - if (!string.IsNullOrWhiteSpace(contentPath)) - { - _owner.LoadApplication(contentPath, false, "Mii Applet"); - } - } - - public static void OpenRyujinxFolder() - { - OpenHelper.OpenFolder(AppDataManager.BaseDirPath); - } - - public static void OpenLogsFolder() - { - string logPath = Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "Logs"); - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); - } - - public void ToggleFullscreen() - { - if (Environment.TickCount64 - _lastFullscreenToggle < HotKeyPressDelayMs) - { - return; - } - - _lastFullscreenToggle = Environment.TickCount64; - - if (_owner.WindowState == WindowState.FullScreen) - { - _owner.WindowState = WindowState.Normal; - - if (IsGameRunning) - { - ShowMenuAndStatusBar = true; - } - } - else - { - _owner.WindowState = WindowState.FullScreen; - - if (IsGameRunning) - { - ShowMenuAndStatusBar = false; - } - } - - OnPropertyChanged(nameof(IsFullScreen)); - } - - public bool IsFullScreen => _owner.WindowState == WindowState.FullScreen; - - public void ToggleDockMode() - { - if (IsGameRunning) - { - ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value; - } - } - - public async void ExitCurrentState() - { - if (_owner.WindowState == WindowState.FullScreen) - { - ToggleFullscreen(); - } - else if (IsGameRunning) - { - await Task.Delay(100); - - _owner.AppHost?.ShowExitPrompt(); - } - } - - public async void OpenSettings() - { - _owner.SettingsWindow = new(_owner.VirtualFileSystem, _owner.ContentManager); - - await _owner.SettingsWindow.ShowDialog(_owner); - - LoadConfigurableHotKeys(); - } - - public async void ManageProfiles() - { - await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem, _owner.LibHacHorizonManager.RyujinxClient); - } - - public async void OpenAboutWindow() - { - await new AboutWindow().ShowDialog(_owner); - } - - public void ChangeLanguage(object obj) - { - LocaleManager.Instance.LoadDefaultLanguage(); - LocaleManager.Instance.LoadLanguage((string)obj); - } - - private void ProgressHandler<T>(T state, int current, int total) where T : Enum - { - try - { - ProgressMaximum = total; - ProgressValue = current; - - switch (state) - { - case PtcLoadingState ptcState: - CacheLoadStatus = $"{current} / {total}"; - switch (ptcState) - { - case PtcLoadingState.Start: - case PtcLoadingState.Loading: - LoadHeading = LocaleManager.Instance["CompilingPPTC"]; - IsLoadingIndeterminate = false; - break; - case PtcLoadingState.Loaded: - LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName); - IsLoadingIndeterminate = true; - CacheLoadStatus = ""; - break; - } - break; - case ShaderCacheLoadingState shaderCacheState: - CacheLoadStatus = $"{current} / {total}"; - switch (shaderCacheState) - { - case ShaderCacheLoadingState.Start: - case ShaderCacheLoadingState.Loading: - LoadHeading = LocaleManager.Instance["CompilingShaders"]; - IsLoadingIndeterminate = false; - break; - case ShaderCacheLoadingState.Loaded: - LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName); - IsLoadingIndeterminate = true; - CacheLoadStatus = ""; - break; - } - break; - default: - throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"); - } - } - catch (Exception) { } - } - - public void OpenUserSaveDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - Task.Run(() => - { - if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]); - }); - - return; - } - - UserId userId = new((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low); - SaveDataFilter saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default); - OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber); - }); - } - } - - public void ToggleFavorite() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - selection.Favorite = !selection.Favorite; - - ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata => - { - appMetadata.Favorite = selection.Favorite; - }); - - RefreshView(); - } - } - - public void OpenModsDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath(); - string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, selection.TitleId); - - OpenHelper.OpenFolder(titleModsPath); - } - } - - public void OpenSdModsDirectory() - { - ApplicationData selection = SelectedApplication; - - if (selection != null) - { - string sdModsBasePath = _owner.VirtualFileSystem.ModLoader.GetSdModsBasePath(); - string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId); - - OpenHelper.OpenFolder(titleModsPath); - } - } - - public void OpenPtcDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu"); - string mainPath = Path.Combine(ptcDir, "0"); - string backupPath = Path.Combine(ptcDir, "1"); - - if (!Directory.Exists(ptcDir)) - { - Directory.CreateDirectory(ptcDir); - Directory.CreateDirectory(mainPath); - Directory.CreateDirectory(backupPath); - } - - OpenHelper.OpenFolder(ptcDir); - } - } - - public async void PurgePtcCache() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0")); - DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1")); - - // FIXME: Found a way to reproduce the bold effect on the title name (fork?). - UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"], - string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName), - LocaleManager.Instance["InputDialogYes"], - LocaleManager.Instance["InputDialogNo"], - LocaleManager.Instance["RyujinxConfirm"]); - - List<FileInfo> cacheFiles = new(); - - if (mainDir.Exists) - { - cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache")); - } - - if (backupDir.Exists) - { - cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache")); - } - - if (cacheFiles.Count > 0 && result == UserResult.Yes) - { - foreach (FileInfo file in cacheFiles) - { - try - { - file.Delete(); - } - catch (Exception e) - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], file.Name, e)); - } - } - } - } - } - - public void OpenShaderCacheDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"); - - if (!Directory.Exists(shaderCacheDir)) - { - Directory.CreateDirectory(shaderCacheDir); - } - - OpenHelper.OpenFolder(shaderCacheDir); - } - } - - public void SimulateWakeUpMessage() - { - _owner.AppHost.Device.System.SimulateWakeUpMessage(); - } - - public async void PurgeShaderCache() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader")); - - // FIXME: Found a way to reproduce the bold effect on the title name (fork?). - UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"], - string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName), - LocaleManager.Instance["InputDialogYes"], - LocaleManager.Instance["InputDialogNo"], - LocaleManager.Instance["RyujinxConfirm"]); - - List<DirectoryInfo> oldCacheDirectories = new(); - List<FileInfo> newCacheFiles = new(); - - if (shaderCacheDir.Exists) - { - oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*")); - newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc")); - newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data")); - } - - if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0) && result == UserResult.Yes) - { - foreach (DirectoryInfo directory in oldCacheDirectories) - { - try - { - directory.Delete(true); - } - catch (Exception e) - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], directory.Name, e)); - } - } - } - - foreach (FileInfo file in newCacheFiles) - { - try - { - file.Delete(); - } - catch (Exception e) - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["ShaderCachePurgeError"], file.Name, e)); - } - } - } - } - - public async void CheckForUpdates() - { - if (Updater.CanUpdate(true, _owner)) - { - await Updater.BeginParse(_owner, true); - } - } - - public async void OpenTitleUpdateManager() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - await new TitleUpdateWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner); - } - } - - public async void OpenDownloadableContentManager() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - await new DownloadableContentManagerWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner); - } - } - - public async void OpenCheatManager() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - await new CheatWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner); - } - } - - public async void OpenCheatManagerForCurrentApp() - { - if (!IsGameRunning) - { - return; - } - - ApplicationLoader application = _owner.AppHost.Device.Application; - if (application != null) - { - await new CheatWindow(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName).ShowDialog(_owner); - - _owner.AppHost.Device.EnableCheats(); - } - } - - public void OpenDeviceSaveDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - Task.Run(() => - { - if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]); - }); - - return; - } - - var saveDataFilter = SaveDataFilter.Make(titleIdNumber, SaveDataType.Device, userId: default, saveDataId: default, index: default); - OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber); - }); - } - } - - public void OpenBcatSaveDirectory() - { - ApplicationData selection = SelectedApplication; - if (selection != null) - { - Task.Run(() => - { - if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]); - }); - - return; - } - - var saveDataFilter = SaveDataFilter.Make(titleIdNumber, SaveDataType.Bcat, userId: default, saveDataId: default, index: default); - OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber); - }); - } - } - - private void OpenSaveDirectory(in SaveDataFilter filter, ApplicationData data, ulong titleId) - { - ApplicationHelper.OpenSaveDir(in filter, titleId, data.ControlHolder, data.TitleName); - } - - private async void ExtractLogo() - { - var selection = SelectedApplication; - if (selection != null) - { - await ApplicationHelper.ExtractSection(NcaSectionType.Logo, selection.Path); - } - } - - private async void ExtractRomFs() - { - var selection = SelectedApplication; - if (selection != null) - { - await ApplicationHelper.ExtractSection(NcaSectionType.Data, selection.Path); - } - } - - private async void ExtractExeFs() - { - var selection = SelectedApplication; - if (selection != null) - { - await ApplicationHelper.ExtractSection(NcaSectionType.Code, selection.Path); - } - } - - public void CloseWindow() - { - _owner.Close(); - } - - private async Task HandleFirmwareInstallation(string filename) - { - try - { - SystemVersion firmwareVersion = _owner.ContentManager.VerifyFirmwarePackage(filename); - - if (firmwareVersion == null) - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareNotFoundErrorMessage"], filename)); - - return; - } - - string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString); - - SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion(); - - string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString); - - if (currentVersion != null) - { - dialogMessage += string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSubMessage"], currentVersion.VersionString); - } - - dialogMessage += LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallConfirmMessage"]; - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - dialogTitle, - dialogMessage, - LocaleManager.Instance["InputDialogYes"], - LocaleManager.Instance["InputDialogNo"], - LocaleManager.Instance["RyujinxConfirm"]); - - UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallWaitMessage"]); - - if (result == UserResult.Yes) - { - Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}"); - - Thread thread = new(() => - { - Dispatcher.UIThread.InvokeAsync(delegate - { - waitingDialog.Show(); - }); - - try - { - _owner.ContentManager.InstallFirmware(filename); - - Dispatcher.UIThread.InvokeAsync(async delegate - { - waitingDialog.Close(); - - string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString); - - await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]); - - Logger.Info?.Print(LogClass.Application, message); - - // Purge Applet Cache. - - DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache")); - - if (miiEditorCacheFolder.Exists) - { - miiEditorCacheFolder.Delete(true); - } - }); - } - catch (Exception ex) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - waitingDialog.Close(); - - await ContentDialogHelper.CreateErrorDialog(ex.Message); - }); - } - finally - { - _owner.RefreshFirmwareStatus(); - } - }); - - thread.Name = "GUI.FirmwareInstallerThread"; - thread.Start(); - } - } - catch (LibHac.Common.Keys.MissingKeyException ex) - { - Logger.Error?.Print(LogClass.Application, ex.ToString()); - - Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner)); - } - catch (Exception ex) - { - await ContentDialogHelper.CreateErrorDialog(ex.Message); - } - } - - public async void InstallFirmwareFromFile() - { - OpenFileDialog dialog = new() { AllowMultiple = false }; - dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance["FileDialogAllTypes"], Extensions = { "xci", "zip" } }); - dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } }); - dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } }); - - string[] file = await dialog.ShowAsync(_owner); - - if (file != null && file.Length > 0) - { - await HandleFirmwareInstallation(file[0]); - } - } - - public async void InstallFirmwareFromFolder() - { - OpenFolderDialog dialog = new(); - - string folder = await dialog.ShowAsync(_owner); - - if (!string.IsNullOrWhiteSpace(folder)) - { - await HandleFirmwareInstallation(folder); - } - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs deleted file mode 100644 index c752697b..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs +++ /dev/null @@ -1,520 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Threading; -using DynamicData; -using LibHac.Tools.FsSystem; -using Ryujinx.Audio.Backends.OpenAL; -using Ryujinx.Audio.Backends.SDL2; -using Ryujinx.Audio.Backends.SoundIo; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.GraphicsDriver; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Vulkan; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Input; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - internal class SettingsViewModel : BaseModel - { - private readonly VirtualFileSystem _virtualFileSystem; - private readonly ContentManager _contentManager; - private readonly StyleableWindow _owner; - private TimeZoneContentManager _timeZoneContentManager; - - private readonly List<string> _validTzRegions; - - private float _customResolutionScale; - private int _resolutionScale; - private int _graphicsBackendMultithreadingIndex; - private float _previousVolumeLevel; - private float _volume; - private bool _isVulkanAvailable = true; - private bool _directoryChanged = false; - private List<string> _gpuIds = new List<string>(); - private KeyboardHotkeys _keyboardHotkeys; - private int _graphicsBackendIndex; - - public int ResolutionScale - { - get => _resolutionScale; - set - { - _resolutionScale = value; - - OnPropertyChanged(nameof(CustomResolutionScale)); - OnPropertyChanged(nameof(IsCustomResolutionScaleActive)); - } - } - public int GraphicsBackendMultithreadingIndex - { - get => _graphicsBackendMultithreadingIndex; - set - { - _graphicsBackendMultithreadingIndex = value; - - if (_owner != null) - { - if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"], - "", - "", - LocaleManager.Instance["InputDialogOk"], - LocaleManager.Instance["DialogSettingsBackendThreadingWarningTitle"]); - }); - } - } - - OnPropertyChanged(); - } - } - - public float CustomResolutionScale - { - get => _customResolutionScale; - set - { - _customResolutionScale = MathF.Round(value, 1); - - OnPropertyChanged(); - } - } - - public bool IsVulkanAvailable - { - get => _isVulkanAvailable; - set - { - _isVulkanAvailable = value; - - OnPropertyChanged(); - } - } - - public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS(); - - public bool DirectoryChanged - { - get => _directoryChanged; - set - { - _directoryChanged = value; - - OnPropertyChanged(); - } - } - - public bool IsMacOS - { - get => OperatingSystem.IsMacOS(); - } - - public bool EnableDiscordIntegration { get; set; } - public bool CheckUpdatesOnStart { get; set; } - public bool ShowConfirmExit { get; set; } - public bool HideCursorOnIdle { get; set; } - public bool EnableDockedMode { get; set; } - public bool EnableKeyboard { get; set; } - public bool EnableMouse { get; set; } - public bool EnableVsync { get; set; } - public bool EnablePptc { get; set; } - public bool EnableInternetAccess { get; set; } - public bool EnableFsIntegrityChecks { get; set; } - public bool IgnoreMissingServices { get; set; } - public bool ExpandDramSize { get; set; } - public bool EnableShaderCache { get; set; } - public bool EnableTextureRecompression { get; set; } - public bool EnableMacroHLE { get; set; } - public bool EnableFileLog { get; set; } - public bool EnableStub { get; set; } - public bool EnableInfo { get; set; } - public bool EnableWarn { get; set; } - public bool EnableError { get; set; } - public bool EnableTrace { get; set; } - public bool EnableGuest { get; set; } - public bool EnableFsAccessLog { get; set; } - public bool EnableDebug { get; set; } - public bool IsOpenAlEnabled { get; set; } - public bool IsSoundIoEnabled { get; set; } - public bool IsSDL2Enabled { get; set; } - public bool EnableCustomTheme { get; set; } - public bool IsCustomResolutionScaleActive => _resolutionScale == 0; - public bool IsVulkanSelected => GraphicsBackendIndex == 0; - - public string TimeZone { get; set; } - public string ShaderDumpPath { get; set; } - public string CustomThemePath { get; set; } - - public int Language { get; set; } - public int Region { get; set; } - public int FsGlobalAccessLogMode { get; set; } - public int AudioBackend { get; set; } - public int MaxAnisotropy { get; set; } - public int AspectRatio { get; set; } - public int OpenglDebugLevel { get; set; } - public int MemoryMode { get; set; } - public int BaseStyleIndex { get; set; } - public int GraphicsBackendIndex - { - get => _graphicsBackendIndex; - set - { - _graphicsBackendIndex = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(IsVulkanSelected)); - } - } - - public int PreferredGpuIndex { get; set; } - - public float Volume - { - get => _volume; - set - { - _volume = value; - - ConfigurationState.Instance.System.AudioVolume.Value = (float)(_volume / 100); - - OnPropertyChanged(); - } - } - - public DateTimeOffset DateOffset { get; set; } - public TimeSpan TimeOffset { get; set; } - public AvaloniaList<TimeZone> TimeZones { get; set; } - public AvaloniaList<string> GameDirectories { get; set; } - public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; } - - public KeyboardHotkeys KeyboardHotkeys - { - get => _keyboardHotkeys; - set - { - _keyboardHotkeys = value; - - OnPropertyChanged(); - } - } - - public IGamepadDriver AvaloniaKeyboardDriver { get; } - - public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager, StyleableWindow owner) : this() - { - _virtualFileSystem = virtualFileSystem; - _contentManager = contentManager; - _owner = owner; - if (Program.PreviewerDetached) - { - LoadTimeZones(); - AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); - } - } - - public SettingsViewModel() - { - GameDirectories = new AvaloniaList<string>(); - TimeZones = new AvaloniaList<TimeZone>(); - AvailableGpus = new ObservableCollection<ComboBoxItem>(); - _validTzRegions = new List<string>(); - - CheckSoundBackends(); - - if (Program.PreviewerDetached) - { - LoadAvailableGpus(); - LoadCurrentConfiguration(); - } - } - - public void CheckSoundBackends() - { - IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported; - IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported; - IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported; - } - - private unsafe void LoadAvailableGpus() - { - _gpuIds = new List<string>(); - List<string> names = new List<string>(); - var devices = VulkanRenderer.GetPhysicalDevices(); - - if (devices.Length == 0) - { - IsVulkanAvailable = false; - GraphicsBackendIndex = 1; - } - else - { - foreach (var device in devices) - { - _gpuIds.Add(device.Id); - names.Add($"{device.Name} {(device.IsDiscrete ? "(dGPU)" : "")}"); - } - } - - AvailableGpus.Clear(); - AvailableGpus.AddRange(names.Select(x => new ComboBoxItem() { Content = x })); - } - - public void LoadTimeZones() - { - _timeZoneContentManager = new TimeZoneContentManager(); - - _timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None); - - foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets()) - { - int hours = Math.DivRem(offset, 3600, out int seconds); - int minutes = Math.Abs(seconds) / 60; - - string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr; - - TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2)); - - _validTzRegions.Add(location); - } - } - - public void ValidateAndSetTimeZone(string location) - { - if (_validTzRegions.Contains(location)) - { - TimeZone = location; - } - } - - public async void BrowseTheme() - { - var dialog = new OpenFileDialog() - { - Title = LocaleManager.Instance["SettingsSelectThemeFileDialogTitle"], - AllowMultiple = false - }; - - dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance["SettingsXamlThemeFile"] }); - - var file = await dialog.ShowAsync(_owner); - - if (file != null && file.Length > 0) - { - CustomThemePath = file[0]; - OnPropertyChanged(nameof(CustomThemePath)); - } - } - - public void LoadCurrentConfiguration() - { - ConfigurationState config = ConfigurationState.Instance; - - GameDirectories.Clear(); - GameDirectories.AddRange(config.Ui.GameDirs.Value); - - EnableDiscordIntegration = config.EnableDiscordIntegration; - CheckUpdatesOnStart = config.CheckUpdatesOnStart; - ShowConfirmExit = config.ShowConfirmExit; - HideCursorOnIdle = config.HideCursorOnIdle; - EnableDockedMode = config.System.EnableDockedMode; - EnableKeyboard = config.Hid.EnableKeyboard; - EnableMouse = config.Hid.EnableMouse; - EnableVsync = config.Graphics.EnableVsync; - EnablePptc = config.System.EnablePtc; - EnableInternetAccess = config.System.EnableInternetAccess; - EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; - IgnoreMissingServices = config.System.IgnoreMissingServices; - ExpandDramSize = config.System.ExpandRam; - EnableShaderCache = config.Graphics.EnableShaderCache; - EnableTextureRecompression = config.Graphics.EnableTextureRecompression; - EnableMacroHLE = config.Graphics.EnableMacroHLE; - EnableFileLog = config.Logger.EnableFileLog; - EnableStub = config.Logger.EnableStub; - EnableInfo = config.Logger.EnableInfo; - EnableWarn = config.Logger.EnableWarn; - EnableError = config.Logger.EnableError; - EnableTrace = config.Logger.EnableTrace; - EnableGuest = config.Logger.EnableGuest; - EnableDebug = config.Logger.EnableDebug; - EnableFsAccessLog = config.Logger.EnableFsAccessLog; - EnableCustomTheme = config.Ui.EnableCustomTheme; - Volume = config.System.AudioVolume * 100; - - GraphicsBackendMultithreadingIndex = (int)config.Graphics.BackendThreading.Value; - - OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value; - - TimeZone = config.System.TimeZone; - ShaderDumpPath = config.Graphics.ShadersDumpPath; - CustomThemePath = config.Ui.CustomThemePath; - BaseStyleIndex = config.Ui.BaseStyle == "Light" ? 0 : 1; - GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value; - - PreferredGpuIndex = _gpuIds.Contains(config.Graphics.PreferredGpu) ? _gpuIds.IndexOf(config.Graphics.PreferredGpu) : 0; - - Language = (int)config.System.Language.Value; - Region = (int)config.System.Region.Value; - FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode; - AudioBackend = (int)config.System.AudioBackend.Value; - MemoryMode = (int)config.System.MemoryManagerMode.Value; - - float anisotropy = config.Graphics.MaxAnisotropy; - - MaxAnisotropy = anisotropy == -1 ? 0 : (int)(MathF.Log2(anisotropy)); - AspectRatio = (int)config.Graphics.AspectRatio.Value; - - int resolution = config.Graphics.ResScale; - - ResolutionScale = resolution == -1 ? 0 : resolution; - CustomResolutionScale = config.Graphics.ResScaleCustom; - - DateTime dateTimeOffset = DateTime.Now.AddSeconds(config.System.SystemTimeOffset); - - DateOffset = dateTimeOffset.Date; - TimeOffset = dateTimeOffset.TimeOfDay; - - KeyboardHotkeys = config.Hid.Hotkeys.Value; - - _previousVolumeLevel = Volume; - } - - public void SaveSettings() - { - ConfigurationState config = ConfigurationState.Instance; - - if (_directoryChanged) - { - List<string> gameDirs = new List<string>(GameDirectories); - config.Ui.GameDirs.Value = gameDirs; - } - - if (_validTzRegions.Contains(TimeZone)) - { - config.System.TimeZone.Value = TimeZone; - } - - config.Logger.EnableError.Value = EnableError; - config.Logger.EnableTrace.Value = EnableTrace; - config.Logger.EnableWarn.Value = EnableWarn; - config.Logger.EnableInfo.Value = EnableInfo; - config.Logger.EnableStub.Value = EnableStub; - config.Logger.EnableDebug.Value = EnableDebug; - config.Logger.EnableGuest.Value = EnableGuest; - config.Logger.EnableFsAccessLog.Value = EnableFsAccessLog; - config.Logger.EnableFileLog.Value = EnableFileLog; - config.Logger.GraphicsDebugLevel.Value = (GraphicsDebugLevel)OpenglDebugLevel; - config.System.EnableDockedMode.Value = EnableDockedMode; - config.EnableDiscordIntegration.Value = EnableDiscordIntegration; - config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; - config.ShowConfirmExit.Value = ShowConfirmExit; - config.HideCursorOnIdle.Value = HideCursorOnIdle; - config.Graphics.EnableVsync.Value = EnableVsync; - config.Graphics.EnableShaderCache.Value = EnableShaderCache; - config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression; - config.Graphics.EnableMacroHLE.Value = EnableMacroHLE; - config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex; - config.System.EnablePtc.Value = EnablePptc; - config.System.EnableInternetAccess.Value = EnableInternetAccess; - config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; - config.System.IgnoreMissingServices.Value = IgnoreMissingServices; - config.System.ExpandRam.Value = ExpandDramSize; - config.Hid.EnableKeyboard.Value = EnableKeyboard; - config.Hid.EnableMouse.Value = EnableMouse; - config.Ui.CustomThemePath.Value = CustomThemePath; - config.Ui.EnableCustomTheme.Value = EnableCustomTheme; - config.Ui.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; - config.System.Language.Value = (Language)Language; - config.System.Region.Value = (Region)Region; - - config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex); - - if (ConfigurationState.Instance.Graphics.BackendThreading != (BackendThreading)GraphicsBackendMultithreadingIndex) - { - DriverUtilities.ToggleOGLThreading(GraphicsBackendMultithreadingIndex == (int)BackendThreading.Off); - } - - config.Graphics.BackendThreading.Value = (BackendThreading)GraphicsBackendMultithreadingIndex; - - TimeSpan systemTimeOffset = DateOffset - DateTime.Now; - - config.System.SystemTimeOffset.Value = systemTimeOffset.Seconds; - config.Graphics.ShadersDumpPath.Value = ShaderDumpPath; - config.System.FsGlobalAccessLogMode.Value = FsGlobalAccessLogMode; - config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode; - - float anisotropy = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy); - - config.Graphics.MaxAnisotropy.Value = anisotropy; - config.Graphics.AspectRatio.Value = (AspectRatio)AspectRatio; - config.Graphics.ResScale.Value = ResolutionScale == 0 ? -1 : ResolutionScale; - config.Graphics.ResScaleCustom.Value = CustomResolutionScale; - config.System.AudioVolume.Value = Volume / 100; - - AudioBackend audioBackend = (AudioBackend)AudioBackend; - if (audioBackend != config.System.AudioBackend.Value) - { - config.System.AudioBackend.Value = audioBackend; - - Logger.Info?.Print(LogClass.Application, $"AudioBackend toggled to: {audioBackend}"); - } - - config.Hid.Hotkeys.Value = KeyboardHotkeys; - - config.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - MainWindow.UpdateGraphicsConfig(); - - _previousVolumeLevel = Volume; - - if (_owner is SettingsWindow owner) - { - owner.ControllerSettings?.SaveCurrentProfile(); - } - - if (_owner.Owner is MainWindow window && _directoryChanged) - { - window.ViewModel.LoadApplications(); - } - - _directoryChanged = false; - } - - public void RevertIfNotSaved() - { - Program.ReloadConfig(); - } - - public void ApplyButton() - { - SaveSettings(); - } - - public void OkButton() - { - SaveSettings(); - _owner.Close(); - } - - public void CancelButton() - { - RevertIfNotSaved(); - _owner.Close(); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Ava/Ui/ViewModels/UserProfileViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/UserProfileViewModel.cs deleted file mode 100644 index eb9f69d6..00000000 --- a/Ryujinx.Ava/Ui/ViewModels/UserProfileViewModel.cs +++ /dev/null @@ -1,213 +0,0 @@ -using Avalonia; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Shim; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile; - -namespace Ryujinx.Ava.Ui.ViewModels -{ - public class UserProfileViewModel : BaseModel, IDisposable - { - private readonly NavigationDialogHost _owner; - - private UserProfile _selectedProfile; - private UserProfile _highlightedProfile; - - public UserProfileViewModel() - { - Profiles = new ObservableCollection<UserProfile>(); - LostProfiles = new ObservableCollection<UserProfile>(); - } - - public UserProfileViewModel(NavigationDialogHost owner) : this() - { - _owner = owner; - - LoadProfiles(); - } - - public ObservableCollection<UserProfile> Profiles { get; set; } - - public ObservableCollection<UserProfile> LostProfiles { get; set; } - - public UserProfile SelectedProfile - { - get => _selectedProfile; - set - { - _selectedProfile = value; - - OnPropertyChanged(nameof(SelectedProfile)); - OnPropertyChanged(nameof(IsHighlightedProfileDeletable)); - OnPropertyChanged(nameof(IsHighlightedProfileEditable)); - } - } - - public bool IsHighlightedProfileEditable => _highlightedProfile != null; - - public bool IsHighlightedProfileDeletable => _highlightedProfile != null && _highlightedProfile.UserId != AccountManager.DefaultUserId; - - public UserProfile HighlightedProfile - { - get => _highlightedProfile; - set - { - _highlightedProfile = value; - - OnPropertyChanged(nameof(HighlightedProfile)); - OnPropertyChanged(nameof(IsHighlightedProfileDeletable)); - OnPropertyChanged(nameof(IsHighlightedProfileEditable)); - } - } - - public void Dispose() { } - - public void LoadProfiles() - { - Profiles.Clear(); - LostProfiles.Clear(); - - var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open); - - foreach (var profile in profiles) - { - Profiles.Add(new UserProfile(profile, _owner)); - } - - SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId); - - if (SelectedProfile == null) - { - SelectedProfile = Profiles.First(); - - if (SelectedProfile != null) - { - _owner.AccountManager.OpenUser(_selectedProfile.UserId); - } - } - - var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, - default, saveDataId: default, index: default); - - using var saveDataIterator = new UniqueRef<SaveDataIterator>(); - - _owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); - - Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; - - HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new HashSet<HLE.HOS.Services.Account.Acc.UserId>(); - - while (true) - { - saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure(); - - if (readCount == 0) - { - break; - } - - for (int i = 0; i < readCount; i++) - { - var save = saveDataInfo[i]; - var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High); - if (Profiles.FirstOrDefault( x=> x.UserId == id) == null) - { - lostAccounts.Add(id); - } - } - } - - foreach(var account in lostAccounts) - { - LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner)); - } - } - - public void AddUser() - { - UserProfile userProfile = null; - - _owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true)); - } - - public async void ManageSaves() - { - UserProfile userProfile = _highlightedProfile ?? SelectedProfile; - - SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem); - - ContentDialog contentDialog = new ContentDialog - { - Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name), - PrimaryButtonText = "", - SecondaryButtonText = "", - CloseButtonText = LocaleManager.Instance["UserProfilesClose"], - Content = manager, - Padding = new Thickness(0) - }; - - await contentDialog.ShowAsync(); - } - - public void EditUser() - { - _owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false)); - } - - public async void DeleteUser() - { - if (_highlightedProfile != null) - { - var lastUserId = _owner.AccountManager.LastOpenedUser.UserId; - - if (_highlightedProfile.UserId == lastUserId) - { - // If we are deleting the currently open profile, then we must open something else before deleting. - var profile = Profiles.FirstOrDefault(x => x.UserId != lastUserId); - - if (profile == null) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]); - }); - - return; - } - - _owner.AccountManager.OpenUser(profile.UserId); - } - - var result = - await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "", - LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], ""); - - if (result == UserResult.Yes) - { - _owner.AccountManager.DeleteUser(_highlightedProfile.UserId); - } - } - - LoadProfiles(); - } - - public void GoBack() - { - _owner.GoBack(); - } - - public void RecoverLostAccounts() - { - _owner.Navigate(typeof(UserRecoverer), (this._owner, this)); - } - } -}
\ No newline at end of file |
