Add CommunityToolkit.Mvvm

Use [ObservableProperty] attribute, which greatly reduces or eliminates boilerplate code needed to generate observable properties

Co-authored-by: GreemDev <greemdev@ryujinx.app>
This commit is contained in:
KeatonTheBot
2026-01-14 16:58:45 -06:00
co-authored by GreemDev
parent 0d29b77a14
commit 7d0947cac6
25 changed files with 433 additions and 1883 deletions
+2 -1
View File
@@ -11,6 +11,7 @@
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.1" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.1" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="Concentus" Version="2.2.2" />
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
<PackageVersion Include="DynamicData" Version="9.4.1" />
@@ -52,4 +53,4 @@
<PackageVersion Include="System.Management" Version="10.0.1" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.4-a40db6c" />
</ItemGroup>
</Project>
</Project>
+1
View File
@@ -32,6 +32,7 @@
<PackageReference Include="Svg.Controls.Avalonia" />
<PackageReference Include="Svg.Controls.Skia.Avalonia" />
<PackageReference Include="CommandLineParser" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="DynamicData" />
<PackageReference Include="FluentAvaloniaUI" />
+55 -335
View File
@@ -1,12 +1,12 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using System;
namespace Ryujinx.Ava.UI.Models.Input
{
public class GamepadInputConfig : BaseModel
public partial class GamepadInputConfig : BaseModel
{
public bool EnableCemuHookMotion { get; set; }
public string DsuServerHost { get; set; }
@@ -24,390 +24,110 @@ namespace Ryujinx.Ava.UI.Models.Input
public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; }
[ObservableProperty]
private StickInputId _leftJoystick;
public StickInputId LeftJoystick
{
get => _leftJoystick;
set
{
_leftJoystick = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _leftInvertStickX;
public bool LeftInvertStickX
{
get => _leftInvertStickX;
set
{
_leftInvertStickX = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _leftInvertStickY;
public bool LeftInvertStickY
{
get => _leftInvertStickY;
set
{
_leftInvertStickY = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _leftRotate90;
public bool LeftRotate90
{
get => _leftRotate90;
set
{
_leftRotate90 = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _leftStickButton;
public GamepadInputId LeftStickButton
{
get => _leftStickButton;
set
{
_leftStickButton = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private StickInputId _rightJoystick;
public StickInputId RightJoystick
{
get => _rightJoystick;
set
{
_rightJoystick = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _rightInvertStickX;
public bool RightInvertStickX
{
get => _rightInvertStickX;
set
{
_rightInvertStickX = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _rightInvertStickY;
public bool RightInvertStickY
{
get => _rightInvertStickY;
set
{
_rightInvertStickY = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _rightRotate90;
public bool RightRotate90
{
get => _rightRotate90;
set
{
_rightRotate90 = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _rightStickButton;
public GamepadInputId RightStickButton
{
get => _rightStickButton;
set
{
_rightStickButton = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _dpadUp;
public GamepadInputId DpadUp
{
get => _dpadUp;
set
{
_dpadUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _dpadDown;
public GamepadInputId DpadDown
{
get => _dpadDown;
set
{
_dpadDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _dpadLeft;
public GamepadInputId DpadLeft
{
get => _dpadLeft;
set
{
_dpadLeft = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _dpadRight;
public GamepadInputId DpadRight
{
get => _dpadRight;
set
{
_dpadRight = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _buttonL;
public GamepadInputId ButtonL
{
get => _buttonL;
set
{
_buttonL = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonMinus;
public GamepadInputId ButtonMinus
{
get => _buttonMinus;
set
{
_buttonMinus = value;
OnPropertyChanged();
}
}
private GamepadInputId _leftButtonSl;
public GamepadInputId LeftButtonSl
{
get => _leftButtonSl;
set
{
_leftButtonSl = value;
OnPropertyChanged();
}
}
private GamepadInputId _leftButtonSr;
public GamepadInputId LeftButtonSr
{
get => _leftButtonSr;
set
{
_leftButtonSr = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonZl;
public GamepadInputId ButtonZl
{
get => _buttonZl;
set
{
_buttonZl = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonA;
public GamepadInputId ButtonA
{
get => _buttonA;
set
{
_buttonA = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonB;
public GamepadInputId ButtonB
{
get => _buttonB;
set
{
_buttonB = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonX;
public GamepadInputId ButtonX
{
get => _buttonX;
set
{
_buttonX = value;
OnPropertyChanged();
}
}
private GamepadInputId _buttonY;
public GamepadInputId ButtonY
{
get => _buttonY;
set
{
_buttonY = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _buttonR;
public GamepadInputId ButtonR
{
get => _buttonR;
set
{
_buttonR = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _buttonMinus;
[ObservableProperty]
private GamepadInputId _buttonPlus;
public GamepadInputId ButtonPlus
{
get => _buttonPlus;
set
{
_buttonPlus = value;
OnPropertyChanged();
}
}
private GamepadInputId _rightButtonSl;
public GamepadInputId RightButtonSl
{
get => _rightButtonSl;
set
{
_rightButtonSl = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _leftButtonSl;
private GamepadInputId _rightButtonSr;
public GamepadInputId RightButtonSr
{
get => _rightButtonSr;
set
{
_rightButtonSr = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _leftButtonSr;
[ObservableProperty]
private GamepadInputId _buttonZl;
[ObservableProperty]
private GamepadInputId _buttonZr;
public GamepadInputId ButtonZr
{
get => _buttonZr;
set
{
_buttonZr = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private GamepadInputId _buttonA;
[ObservableProperty]
private GamepadInputId _buttonB;
[ObservableProperty]
private GamepadInputId _buttonX;
[ObservableProperty]
private GamepadInputId _buttonY;
[ObservableProperty]
private GamepadInputId _rightButtonSl;
[ObservableProperty]
private GamepadInputId _rightButtonSr;
[ObservableProperty]
private float _deadzoneLeft;
public float DeadzoneLeft
{
get => _deadzoneLeft;
set
{
_deadzoneLeft = MathF.Round(value, 3);
OnPropertyChanged();
}
}
[ObservableProperty]
private float _deadzoneRight;
public float DeadzoneRight
{
get => _deadzoneRight;
set
{
_deadzoneRight = MathF.Round(value, 3);
OnPropertyChanged();
}
}
[ObservableProperty]
private float _rangeLeft;
public float RangeLeft
{
get => _rangeLeft;
set
{
_rangeLeft = MathF.Round(value, 3);
OnPropertyChanged();
}
}
[ObservableProperty]
private float _rangeRight;
public float RangeRight
{
get => _rangeRight;
set
{
_rangeRight = MathF.Round(value, 3);
OnPropertyChanged();
}
}
[ObservableProperty]
private float _triggerThreshold;
public float TriggerThreshold
{
get => _triggerThreshold;
set
{
_triggerThreshold = MathF.Round(value, 3);
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _enableMotion;
public bool EnableMotion
{
get => _enableMotion;
set
{
_enableMotion = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _enableRumble;
public bool EnableRumble
{
get => _enableRumble;
set
{
_enableRumble = value;
OnPropertyChanged();
}
}
public GamepadInputConfig(InputConfig config)
{
+16 -120
View File
@@ -1,152 +1,48 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid;
namespace Ryujinx.Ava.UI.Models.Input
{
public class HotkeyConfig : BaseModel
public partial class HotkeyConfig : BaseModel
{
[ObservableProperty]
private Key _toggleVSyncMode;
public Key ToggleVSyncMode
{
get => _toggleVSyncMode;
set
{
_toggleVSyncMode = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _screenshot;
public Key Screenshot
{
get => _screenshot;
set
{
_screenshot = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _showUI;
public Key ShowUI
{
get => _showUI;
set
{
_showUI = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _pause;
public Key Pause
{
get => _pause;
set
{
_pause = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _toggleMute;
public Key ToggleMute
{
get => _toggleMute;
set
{
_toggleMute = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _resScaleUp;
public Key ResScaleUp
{
get => _resScaleUp;
set
{
_resScaleUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _resScaleDown;
public Key ResScaleDown
{
get => _resScaleDown;
set
{
_resScaleDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _volumeUp;
public Key VolumeUp
{
get => _volumeUp;
set
{
_volumeUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _volumeDown;
public Key VolumeDown
{
get => _volumeDown;
set
{
_volumeDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _customVSyncIntervalIncrement;
public Key CustomVSyncIntervalIncrement
{
get => _customVSyncIntervalIncrement;
set
{
_customVSyncIntervalIncrement = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _customVSyncIntervalDecrement;
public Key CustomVSyncIntervalDecrement
{
get => _customVSyncIntervalDecrement;
set
{
_customVSyncIntervalDecrement = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _turboMode;
public Key TurboMode
{
get => _turboMode;
set
{
_turboMode = value;
OnPropertyChanged();
}
}
private bool _turboModeWhileHeld;
public bool TurboModeWhileHeld
{
get => _turboModeWhileHeld;
set
{
_turboModeWhileHeld = value;
OnPropertyChanged();
}
}
[ObservableProperty] private bool _turboModeWhileHeld;
public HotkeyConfig(KeyboardHotkeys config)
{
@@ -1,322 +1,99 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard;
namespace Ryujinx.Ava.UI.Models.Input
{
public class KeyboardInputConfig : BaseModel
public partial class KeyboardInputConfig : BaseModel
{
public string Id { get; set; }
public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; }
[ObservableProperty]
private Key _leftStickUp;
public Key LeftStickUp
{
get => _leftStickUp;
set
{
_leftStickUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftStickDown;
public Key LeftStickDown
{
get => _leftStickDown;
set
{
_leftStickDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftStickLeft;
public Key LeftStickLeft
{
get => _leftStickLeft;
set
{
_leftStickLeft = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftStickRight;
public Key LeftStickRight
{
get => _leftStickRight;
set
{
_leftStickRight = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftStickButton;
public Key LeftStickButton
{
get => _leftStickButton;
set
{
_leftStickButton = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _rightStickUp;
public Key RightStickUp
{
get => _rightStickUp;
set
{
_rightStickUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _rightStickDown;
public Key RightStickDown
{
get => _rightStickDown;
set
{
_rightStickDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _rightStickLeft;
public Key RightStickLeft
{
get => _rightStickLeft;
set
{
_rightStickLeft = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _rightStickRight;
public Key RightStickRight
{
get => _rightStickRight;
set
{
_rightStickRight = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _rightStickButton;
public Key RightStickButton
{
get => _rightStickButton;
set
{
_rightStickButton = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _dpadUp;
public Key DpadUp
{
get => _dpadUp;
set
{
_dpadUp = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _dpadDown;
public Key DpadDown
{
get => _dpadDown;
set
{
_dpadDown = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _dpadLeft;
public Key DpadLeft
{
get => _dpadLeft;
set
{
_dpadLeft = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _dpadRight;
public Key DpadRight
{
get => _dpadRight;
set
{
_dpadRight = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _buttonL;
public Key ButtonL
{
get => _buttonL;
set
{
_buttonL = value;
OnPropertyChanged();
}
}
private Key _buttonMinus;
public Key ButtonMinus
{
get => _buttonMinus;
set
{
_buttonMinus = value;
OnPropertyChanged();
}
}
private Key _leftButtonSl;
public Key LeftButtonSl
{
get => _leftButtonSl;
set
{
_leftButtonSl = value;
OnPropertyChanged();
}
}
private Key _leftButtonSr;
public Key LeftButtonSr
{
get => _leftButtonSr;
set
{
_leftButtonSr = value;
OnPropertyChanged();
}
}
private Key _buttonZl;
public Key ButtonZl
{
get => _buttonZl;
set
{
_buttonZl = value;
OnPropertyChanged();
}
}
private Key _buttonA;
public Key ButtonA
{
get => _buttonA;
set
{
_buttonA = value;
OnPropertyChanged();
}
}
private Key _buttonB;
public Key ButtonB
{
get => _buttonB;
set
{
_buttonB = value;
OnPropertyChanged();
}
}
private Key _buttonX;
public Key ButtonX
{
get => _buttonX;
set
{
_buttonX = value;
OnPropertyChanged();
}
}
private Key _buttonY;
public Key ButtonY
{
get => _buttonY;
set
{
_buttonY = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _buttonR;
public Key ButtonR
{
get => _buttonR;
set
{
_buttonR = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _buttonMinus;
[ObservableProperty]
private Key _buttonPlus;
public Key ButtonPlus
{
get => _buttonPlus;
set
{
_buttonPlus = value;
OnPropertyChanged();
}
}
private Key _rightButtonSl;
public Key RightButtonSl
{
get => _rightButtonSl;
set
{
_rightButtonSl = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftButtonSl;
private Key _rightButtonSr;
public Key RightButtonSr
{
get => _rightButtonSr;
set
{
_rightButtonSr = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _leftButtonSr;
[ObservableProperty]
private Key _buttonZl;
[ObservableProperty]
private Key _buttonZr;
public Key ButtonZr
{
get => _buttonZr;
set
{
_buttonZr = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private Key _buttonA;
[ObservableProperty]
private Key _buttonB;
[ObservableProperty]
private Key _buttonX;
[ObservableProperty]
private Key _buttonY;
[ObservableProperty]
private Key _rightButtonSl;
[ObservableProperty]
private Key _rightButtonSr;
public KeyboardInputConfig(InputConfig config)
{
+3 -11
View File
@@ -1,21 +1,13 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
namespace Ryujinx.Ava.UI.Models
{
public class ModModel : BaseModel
public partial class ModModel : BaseModel
{
[ObservableProperty]
private bool _enabled;
public bool Enabled
{
get => _enabled;
set
{
_enabled = value;
OnPropertyChanged();
}
}
public bool InSd { get; }
public string Path { get; }
public string Name { get; }
+5 -22
View File
@@ -1,32 +1,15 @@
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
namespace Ryujinx.Ava.UI.Models
{
public class ProfileImageModel : BaseModel
public partial class ProfileImageModel(string name, byte[] data) : BaseModel
{
public ProfileImageModel(string name, byte[] data)
{
Name = name;
Data = data;
}
public string Name { get; set; }
public byte[] Data { get; set; }
public string Name { get; set; } = name;
public byte[] Data { get; set; } = data;
[ObservableProperty]
private SolidColorBrush _backgroundColor = new(Colors.White);
public SolidColorBrush BackgroundColor
{
get
{
return _backgroundColor;
}
set
{
_backgroundColor = value;
OnPropertyChanged();
}
}
}
}
+9 -29
View File
@@ -1,56 +1,36 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using System;
namespace Ryujinx.Ava.UI.Models
{
public class TempProfile : BaseModel
public partial class TempProfile : BaseModel
{
private readonly UserProfile _profile;
[ObservableProperty]
private byte[] _image;
[ObservableProperty]
private string _name = String.Empty;
private UserId _userId;
public static uint MaxProfileNameLength => 0x20;
public byte[] Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public UserId UserId
{
get => _userId;
get;
set
{
_userId = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UserIdString));
}
}
public string UserIdString => _userId.ToString();
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
public string UserIdString => UserId.ToString();
public TempProfile(UserProfile profile)
{
_profile = profile;
if (_profile != null)
if (profile != null)
{
Image = profile.Image;
Name = profile.Name;
+12 -51
View File
@@ -1,4 +1,5 @@
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Views.User;
@@ -7,66 +8,26 @@ using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
namespace Ryujinx.Ava.UI.Models
{
public class UserProfile : BaseModel
public partial class UserProfile : BaseModel
{
private readonly Profile _profile;
private readonly NavigationDialogHost _owner;
[ObservableProperty]
private byte[] _image;
[ObservableProperty]
private string _name;
[ObservableProperty]
private UserId _userId;
[ObservableProperty]
private bool _isPointerOver;
[ObservableProperty]
private IBrush _backgroundColor;
public byte[] Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public UserId UserId
{
get => _userId;
set
{
_userId = value;
OnPropertyChanged();
}
}
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
public bool IsPointerOver
{
get => _isPointerOver;
set
{
_isPointerOver = value;
OnPropertyChanged();
}
}
public IBrush BackgroundColor
{
get => _backgroundColor;
set
{
_backgroundColor = value;
OnPropertyChanged();
}
}
public UserProfile(Profile profile, NavigationDialogHost owner)
{
_profile = profile;
@@ -1,6 +1,7 @@
using Avalonia.Media.Imaging;
using Avalonia.Styling;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.UI.Common.Configuration;
@@ -8,43 +9,17 @@ using System;
namespace Ryujinx.Ava.UI.ViewModels
{
public class AboutWindowViewModel : BaseModel, IDisposable
public partial class AboutWindowViewModel : BaseModel, IDisposable
{
private Bitmap _gitlabLogo;
[ObservableProperty]
private Bitmap _gitLabLogo;
[ObservableProperty]
private Bitmap _discordLogo;
[ObservableProperty]
private string _version;
public Bitmap GitLabLogo
{
get => _gitlabLogo;
set
{
_gitlabLogo = value;
OnPropertyChanged();
}
}
public Bitmap DiscordLogo
{
get => _discordLogo;
set
{
_discordLogo = value;
OnPropertyChanged();
}
}
public string Version
{
get => _version;
set
{
_version = value;
OnPropertyChanged();
}
}
public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
public string Developers => "KeatonTheBot";
+9 -7
View File
@@ -1,15 +1,17 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
namespace Ryujinx.Ava.UI.ViewModels
{
public class BaseModel : INotifyPropertyChanged
public class BaseModel : ObservableObject
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan<string> propertyNames)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
OnPropertyChanged(firstPropertyName);
foreach (var propertyName in propertyNames)
{
OnPropertyChanged(propertyName);
}
}
}
}
@@ -1,4 +1,5 @@
using Ryujinx.UI.App.Common;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common.Models;
using System.Linq;
@@ -6,30 +7,12 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class DlcSelectViewModel : BaseModel
{
[ObservableProperty]
private DownloadableContentModel[] _dlcs;
private DownloadableContentModel _selectedDlc;
public DownloadableContentModel[] Dlcs
{
get => _dlcs;
set
{
_dlcs = value;
OnPropertyChanged();
}
}
#nullable enable
public DownloadableContentModel? SelectedDlc
{
get => _selectedDlc;
set
{
_selectedDlc = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private DownloadableContentModel? _selectedDlc;
#nullable disable
public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary)
@@ -2,6 +2,7 @@ using Avalonia.Collections;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
@@ -16,13 +17,18 @@ using Application = Avalonia.Application;
namespace Ryujinx.Ava.UI.ViewModels
{
public class DownloadableContentManagerViewModel : BaseModel
public partial class DownloadableContentManagerViewModel : BaseModel
{
private readonly ApplicationLibrary _applicationLibrary;
private AvaloniaList<DownloadableContentModel> _downloadableContents = [];
[ObservableProperty]
private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = [];
[ObservableProperty]
private AvaloniaList<DownloadableContentModel> _views = [];
private bool _showBundledContentNotice = false;
[ObservableProperty]
private bool _showBundledContentNotice;
private string _search;
private readonly ApplicationData _applicationData;
@@ -30,35 +36,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList<DownloadableContentModel> DownloadableContents
{
get => _downloadableContents;
get;
set
{
_downloadableContents = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UpdateCount));
Sort();
}
}
public AvaloniaList<DownloadableContentModel> Views
{
get => _views;
set
{
_views = value;
OnPropertyChanged();
}
}
public AvaloniaList<DownloadableContentModel> SelectedDownloadableContents
{
get => _selectedDownloadableContents;
set
{
_selectedDownloadableContents = value;
OnPropertyChanged();
}
}
} = [];
public string Search
{
@@ -76,16 +62,6 @@ namespace Ryujinx.Ava.UI.ViewModels
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
}
public bool ShowBundledContentNotice
{
get => _showBundledContentNotice;
set
{
_showBundledContentNotice = value;
OnPropertyChanged();
}
}
public DownloadableContentManagerViewModel(ApplicationLibrary applicationLibrary, ApplicationData applicationData)
{
_applicationLibrary = applicationLibrary;
@@ -138,8 +114,8 @@ namespace Ryujinx.Ava.UI.ViewModels
// some reason. so we save the items here and add them back after
var items = SelectedDownloadableContents.ToArray();
_views.Clear();
_views.AddRange(view);
Views.Clear();
Views.AddRange(view);
foreach (DownloadableContentModel item in items)
{
@@ -1,54 +1,51 @@
using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class ControllerInputViewModel : BaseModel
public partial class ControllerInputViewModel : BaseModel
{
private GamepadInputConfig _config;
public GamepadInputConfig Config
{
get => _config;
get;
set
{
_config = value;
field = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
get;
set
{
_visualizer = value;
field = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
get => _isLeft;
get;
set
{
_isLeft = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
private bool _isRight;
public bool IsRight
{
get => _isRight;
get;
set
{
_isRight = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
@@ -56,16 +53,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty]
private SvgImage _image;
public SvgImage Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public readonly InputViewModel ParentModel;
@@ -4,6 +4,7 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Svg.Skia;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers;
@@ -32,7 +33,7 @@ using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class InputViewModel : BaseModel, IDisposable
public partial class InputViewModel : BaseModel, IDisposable
{
private const string Disabled = "disabled";
private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg";
@@ -48,8 +49,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller;
private string _controllerImage;
private int _device;
private object _configViewModel;
[ObservableProperty]
private string _profileName;
private bool _isLoaded;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -76,10 +79,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public object ConfigViewModel
{
get => _configViewModel;
get;
set
{
_configViewModel = value;
field = value;
VisualStick.UpdateConfig(value);
@@ -203,16 +206,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
}
public string ProfileName
{
get => _profileName; set
{
_profileName = value;
OnPropertyChanged();
}
}
public int Device
{
get => _device;
@@ -451,7 +444,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
const string Hyphen = "-";
const int Offset = 1;
return str[(str.IndexOf(Hyphen) + Offset)..];
return str[(str.IndexOf(Hyphen, StringComparison.Ordinal) + Offset)..];
}
public void LoadDevices()
@@ -1,53 +1,50 @@
using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.Models.Input;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class KeyboardInputViewModel : BaseModel
public partial class KeyboardInputViewModel : BaseModel
{
private KeyboardInputConfig _config;
public KeyboardInputConfig Config
{
get => _config;
get;
set
{
_config = value;
field = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
get;
set
{
_visualizer = value;
field = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
get => _isLeft;
get;
set
{
_isLeft = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
private bool _isRight;
public bool IsRight
{
get => _isRight;
get;
set
{
_isRight = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
@@ -55,16 +52,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty]
private SvgImage _image;
public SvgImage Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
public readonly InputViewModel ParentModel;
@@ -1,93 +1,31 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class MotionInputViewModel : BaseModel
public partial class MotionInputViewModel : BaseModel
{
[ObservableProperty]
private int _slot;
public int Slot
{
get => _slot;
set
{
_slot = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private int _altSlot;
public int AltSlot
{
get => _altSlot;
set
{
_altSlot = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private string _dsuServerHost;
public string DsuServerHost
{
get => _dsuServerHost;
set
{
_dsuServerHost = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private int _dsuServerPort;
public int DsuServerPort
{
get => _dsuServerPort;
set
{
_dsuServerPort = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _mirrorInput;
public bool MirrorInput
{
get => _mirrorInput;
set
{
_mirrorInput = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private int _sensitivity;
public int Sensitivity
{
get => _sensitivity;
set
{
_sensitivity = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private double _gyroDeadzone;
public double GyroDeadzone
{
get => _gyroDeadzone;
set
{
_gyroDeadzone = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _enableCemuHookMotion;
public bool EnableCemuHookMotion
{
get => _enableCemuHookMotion;
set
{
_enableCemuHookMotion = value;
OnPropertyChanged();
}
}
}
}
@@ -1,27 +1,13 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public class RumbleInputViewModel : BaseModel
public partial class RumbleInputViewModel : BaseModel
{
[ObservableProperty]
private float _strongRumble;
public float StrongRumble
{
get => _strongRumble;
set
{
_strongRumble = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private float _weakRumble;
public float WeakRumble
{
get => _weakRumble;
set
{
_weakRumble = value;
OnPropertyChanged();
}
}
}
}
+88 -545
View File
@@ -5,6 +5,7 @@ using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
@@ -50,90 +51,84 @@ using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
namespace Ryujinx.Ava.UI.ViewModels
{
public class MainWindowViewModel : BaseModel
public partial class MainWindowViewModel : BaseModel
{
private const int HotKeyPressDelayMs = 500;
private delegate int LoadContentFromFolderDelegate(List<string> dirs, out int numRemoved);
private ObservableCollectionExtended<ApplicationData> _applications;
private string _aspectStatusText;
[ObservableProperty] private ObservableCollectionExtended<ApplicationData> _applications;
[ObservableProperty] private string _aspectRatioStatusText;
private string _loadHeading;
private string _cacheLoadStatus;
[ObservableProperty] private string _loadHeading;
[ObservableProperty] private string _cacheLoadStatus;
[ObservableProperty] private string _dockedStatusText;
[ObservableProperty] private string _fifoStatusText;
[ObservableProperty] private string _gameStatusText;
[ObservableProperty] private string _volumeStatusText;
[ObservableProperty] private string _gpuNameText;
[ObservableProperty] private string _shaderCountText;
[ObservableProperty] private bool _showRightmostSeparator;
[ObservableProperty] private bool _isFullScreen;
[ObservableProperty] private int _progressMaximum;
[ObservableProperty] private int _progressValue;
[ObservableProperty] private long _lastFullscreenToggle = Environment.TickCount64;
[ObservableProperty] private bool _showMenuAndStatusBar = true;
[ObservableProperty] private bool _showStatusSeparator;
[ObservableProperty] private Brush _progressBarForegroundColor;
[ObservableProperty] private Brush _progressBarBackgroundColor;
[ObservableProperty] private Brush _vSyncModeColor;
#nullable enable
[ObservableProperty] private byte[]? _selectedIcon;
#nullable disable
[ObservableProperty] private int _statusBarProgressMaximum;
[ObservableProperty] private int _statusBarProgressValue;
[ObservableProperty] private string _statusBarProgressStatusText;
[ObservableProperty] private bool _statusBarProgressStatusVisible;
[ObservableProperty] private bool _isPaused;
[ObservableProperty] private bool _showContent = true;
[ObservableProperty] private bool _isLoadingIndeterminate = true;
[ObservableProperty] private bool _showAll;
[ObservableProperty] private string _lastScannedAmiiboId;
[ObservableProperty] private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
[ObservableProperty] private float _volumeBeforeMute;
[ObservableProperty] private string _backendText;
[ObservableProperty] private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered;
[ObservableProperty] private Cursor _cursor;
[ObservableProperty] private string _title;
[ObservableProperty] private WindowState _windowState;
[ObservableProperty] private double _windowWidth;
[ObservableProperty] private double _windowHeight;
[ObservableProperty] private bool _isActive;
[ObservableProperty] private bool _isSubMenuOpen;
private ApplicationContextMenu _listAppContextMenu;
private ApplicationContextMenu _gridAppContextMenu;
private bool _isGameRunning;
private string _searchText;
private Timer _searchTimer;
private string _dockedStatusText;
private string _vSyncModeText;
private string _fifoStatusText;
private string _gameStatusText;
private string _volumeStatusText;
private string _gpuStatusText;
private string _shaderCountText;
private bool _isAmiiboRequested;
private bool _showRightmostSeparator;
private bool _isAmiiboBinRequested;
private bool _isGameRunning;
private bool _isFullScreen;
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 _vSyncModeColor;
private byte[] _selectedIcon;
private bool _isAppletMenuActive;
private int _statusBarProgressMaximum;
private int _statusBarProgressValue;
private string _statusBarProgressStatusText;
private bool _statusBarProgressStatusVisible;
private bool _isPaused;
private bool _showContent = true;
private bool _isLoadingIndeterminate = true;
private bool _showAll;
private string _lastScannedAmiiboId;
private bool _statusBarVisible;
private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
private string _showUiKey = "F4";
private string _pauseKey = "F5";
private string _screenshotKey = "F8";
private float _volume;
private float _volumeBeforeMute;
private string _backendText;
private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered;
private bool _canUpdate = true;
private Cursor _cursor;
private string _title;
private ApplicationData _currentApplicationData;
private readonly AutoResetEvent _rendererWaitEvent;
private WindowState _windowState;
private double _windowWidth;
private double _windowHeight;
private int _customVSyncInterval;
private int _customVSyncIntervalPercentageProxy;
private bool _isActive;
private bool _isSubMenuOpen;
private ApplicationData _listSelectedApplication;
private ApplicationData _gridSelectedApplication;
private ApplicationContextMenu _listAppContextMenu;
private ApplicationContextMenu _gridAppContextMenu;
public ApplicationData ListSelectedApplication
{
get => _listSelectedApplication;
get;
set
{
_listSelectedApplication = value;
field = value;
if (_listSelectedApplication != null && _listAppContextMenu == null)
if (field != null && _listAppContextMenu == null)
ListAppContextMenu = new ApplicationContextMenu();
else if (_listSelectedApplication == null && _listAppContextMenu != null)
else if (field == null && _listAppContextMenu != null)
ListAppContextMenu = null;
OnPropertyChanged();
@@ -142,20 +137,20 @@ namespace Ryujinx.Ava.UI.ViewModels
public ApplicationData GridSelectedApplication
{
get => _gridSelectedApplication;
get;
set
{
_gridSelectedApplication = value;
field = value;
if (_gridSelectedApplication != null && _gridAppContextMenu == null)
if (field != null && _gridAppContextMenu == null)
GridAppContextMenu = new ApplicationContextMenu();
else if (_gridSelectedApplication == null && _gridAppContextMenu != null)
else if (field == null && _gridAppContextMenu != null)
GridAppContextMenu = null;
OnPropertyChanged();
}
}
public IEnumerable<LdnGameData> LastLdnGameData;
public MainWindow Window { get; init; }
@@ -169,6 +164,8 @@ namespace Ryujinx.Ava.UI.ViewModels
Applications.ToObservableChangeSet()
.Filter(Filter)
.Sort(GetComparer())
.OnItemAdded(_ => OnPropertyChanged(nameof(AppsObservableList)))
.OnItemRemoved(_ => OnPropertyChanged(nameof(AppsObservableList)))
.Bind(out _appsObservableList)
.Subscribe();
@@ -239,31 +236,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CanUpdate
{
get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false);
get => field && EnableNonGameRunningControls && Updater.CanUpdate(false);
set
{
_canUpdate = value;
OnPropertyChanged();
}
}
public Cursor Cursor
{
get => _cursor;
set
{
_cursor = value;
OnPropertyChanged();
}
}
public ReadOnlyObservableCollection<ApplicationData> AppsObservableList
{
get => _appsObservableList;
set
{
_appsObservableList = value;
field = value;
OnPropertyChanged();
}
}
@@ -290,34 +266,12 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public bool IsPaused
{
get => _isPaused;
set
{
_isPaused = value;
OnPropertyChanged();
}
}
public long LastFullscreenToggle
{
get => _lastFullscreenToggle;
set
{
_lastFullscreenToggle = value;
OnPropertyChanged();
}
}
public bool StatusBarVisible
{
get => _statusBarVisible && EnableNonGameRunningControls;
get => field && EnableNonGameRunningControls;
set
{
_statusBarVisible = value;
field = value;
OnPropertyChanged();
}
@@ -327,17 +281,6 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowFirmwareStatus => !ShowLoadProgress;
public bool ShowRightmostSeparator
{
get => _showRightmostSeparator;
set
{
_showRightmostSeparator = value;
OnPropertyChanged();
}
}
public bool IsGameRunning
{
get => _isGameRunning;
@@ -360,20 +303,20 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsAmiiboRequested
{
get => _isAmiiboRequested && _isGameRunning;
get => field && _isGameRunning;
set
{
_isAmiiboRequested = value;
field = value;
OnPropertyChanged();
}
}
public bool IsAmiiboBinRequested
{
get => _isAmiiboBinRequested && _isGameRunning;
get => field && _isGameRunning;
set
{
_isAmiiboBinRequested = value;
field = value;
OnPropertyChanged();
}
@@ -383,71 +326,16 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowLoadProgress
{
get => _showLoadProgress;
get;
set
{
_showLoadProgress = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowFirmwareStatus));
}
}
public string GameStatusText
{
get => _gameStatusText;
set
{
_gameStatusText = value;
OnPropertyChanged();
}
}
public bool IsFullScreen
{
get => _isFullScreen;
set
{
_isFullScreen = value;
OnPropertyChanged();
}
}
public bool IsSubMenuOpen
{
get => _isSubMenuOpen;
set
{
_isSubMenuOpen = value;
OnPropertyChanged();
}
}
public bool ShowAll
{
get => _showAll;
set
{
_showAll = value;
OnPropertyChanged();
}
}
public string LastScannedAmiiboId
{
get => _lastScannedAmiiboId;
set
{
_lastScannedAmiiboId = value;
OnPropertyChanged();
}
}
public ApplicationData SelectedApplication
{
get
@@ -471,63 +359,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild;
public string LoadHeading
{
get => _loadHeading;
set
{
_loadHeading = value;
OnPropertyChanged();
}
}
public bool HasDlc => ApplicationLibrary.HasDlcs(SelectedApplication.Id);
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 VSyncModeColor
{
get => _vSyncModeColor;
set
{
_vSyncModeColor = value;
OnPropertyChanged();
}
}
public bool ShowCustomVSyncIntervalPicker
{
get
@@ -537,10 +370,8 @@ namespace Ryujinx.Ava.UI.ViewModels
return AppHost.Device.VSyncMode ==
VSyncMode.Custom;
}
else
{
return false;
}
return false;
}
set
{
@@ -598,165 +429,12 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
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 bool StatusBarProgressStatusVisible
{
get => _statusBarProgressStatusVisible;
set
{
_statusBarProgressStatusVisible = value;
OnPropertyChanged();
}
}
public string StatusBarProgressStatusText
{
get => _statusBarProgressStatusText;
set
{
_statusBarProgressStatusText = value;
OnPropertyChanged();
}
}
public string FifoStatusText
{
get => _fifoStatusText;
set
{
_fifoStatusText = value;
OnPropertyChanged();
}
}
public string GpuNameText
{
get => _gpuStatusText;
set
{
_gpuStatusText = value;
OnPropertyChanged();
}
}
public string ShaderCountText
{
get => _shaderCountText;
set
{
_shaderCountText = value;
OnPropertyChanged();
}
}
public string BackendText
{
get => _backendText;
set
{
_backendText = value;
OnPropertyChanged();
}
}
public string VSyncModeText
{
get => _vSyncModeText;
get;
set
{
_vSyncModeText = 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;
field = value;
OnPropertyChanged();
}
@@ -782,112 +460,12 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public float VolumeBeforeMute
{
get => _volumeBeforeMute;
set
{
_volumeBeforeMute = value;
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 IsActive
{
get => _isActive;
set
{
_isActive = value;
OnPropertyChanged();
}
}
public bool ShowContent
{
get => _showContent;
set
{
_showContent = value;
OnPropertyChanged();
}
}
public bool IsAppletMenuActive
{
get => _isAppletMenuActive && EnableNonGameRunningControls;
get => field && EnableNonGameRunningControls;
set
{
_isAppletMenuActive = value;
OnPropertyChanged();
}
}
public WindowState WindowState
{
get => _windowState;
internal set
{
_windowState = value;
OnPropertyChanged();
}
}
public double WindowWidth
{
get => _windowWidth;
set
{
_windowWidth = value;
OnPropertyChanged();
}
}
public double WindowHeight
{
get => _windowHeight;
set
{
_windowHeight = value;
field = value;
OnPropertyChanged();
}
@@ -949,17 +527,6 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public string Title
{
get => _title;
set
{
_title = value;
OnPropertyChanged();
}
}
public bool ShowConsoleVisible
{
get => ConsoleHelper.SetConsoleWindowStateSupported;
@@ -970,27 +537,6 @@ namespace Ryujinx.Ava.UI.ViewModels
get => FileAssociationHelper.IsTypeAssociationSupported;
}
public bool AreMimeTypesRegistered
{
get => _areMimeTypesRegistered;
set {
_areMimeTypesRegistered = value;
OnPropertyChanged();
}
}
public ObservableCollectionExtended<ApplicationData> Applications
{
get => _applications;
set
{
_applications = value;
OnPropertyChanged();
}
}
public Glyph Glyph
{
get => (Glyph)ConfigurationState.Instance.UI.GameListViewMode.Value;
@@ -1225,9 +771,10 @@ namespace Ryujinx.Ava.UI.ViewModels
Applications.ToObservableChangeSet()
.Filter(Filter)
.Sort(GetComparer())
.Bind(out _appsObservableList).AsObservableList();
.Bind(out ReadOnlyObservableCollection<ApplicationData> apps)
.AsObservableList();
OnPropertyChanged(nameof(AppsObservableList));
AppsObservableList = apps;
}
private bool Filter(object arg)
@@ -1338,7 +885,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
catch (MissingKeyException ex)
{
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime)
{
Logger.Error?.Print(LogClass.Application, ex.ToString());
@@ -1570,7 +1117,7 @@ namespace Ryujinx.Ava.UI.ViewModels
VSyncModeText = args.VSyncMode == "Custom" ? "Custom" : "VSync";
ShowCustomVSyncIntervalPicker =
args.VSyncMode == VSyncMode.Custom.ToString();
args.VSyncMode == nameof(VSyncMode.Custom);
DockedStatusText = args.DockedMode;
AspectRatioStatusText = args.AspectRatio;
GameStatusText = args.GameStatus;
@@ -1604,7 +1151,7 @@ namespace Ryujinx.Ava.UI.ViewModels
var dirs = result.Select(it => it.Path.LocalPath).ToList();
var numAdded = onDirsSelected(dirs, out int numRemoved);
var msg = String.Join("\r\n", new string[] {
var msg = String.Join("\r\n", new[] {
string.Format(LocaleManager.Instance[localeMessageRemovedKey], numRemoved),
string.Format(LocaleManager.Instance[localeMessageAddedKey], numAdded)
});
@@ -2288,11 +1835,7 @@ namespace Ryujinx.Ava.UI.ViewModels
switch (operationOutcome)
{
case XCIFileTrimmer.OperationOutcome.Successful:
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
if (desktop.MainWindow is MainWindow mainWindow)
mainWindow.LoadApplications();
}
App.MainWindow.LoadApplications();
break;
}
}
@@ -3,6 +3,7 @@ using Avalonia.Collections;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
@@ -18,12 +19,14 @@ using System.Linq;
namespace Ryujinx.Ava.UI.ViewModels
{
public class ModManagerViewModel : BaseModel
public partial class ModManagerViewModel : BaseModel
{
private readonly string _modJsonPath;
private AvaloniaList<ModModel> _mods = [];
[ObservableProperty]
private AvaloniaList<ModModel> _views = [];
[ObservableProperty]
private AvaloniaList<ModModel> _selectedMods = [];
private string _search;
@@ -35,35 +38,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList<ModModel> Mods
{
get => _mods;
get;
set
{
_mods = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ModCount));
Sort();
}
}
public AvaloniaList<ModModel> Views
{
get => _views;
set
{
_views = value;
OnPropertyChanged();
}
}
public AvaloniaList<ModModel> SelectedMods
{
get => _selectedMods;
set
{
_selectedMods = value;
OnPropertyChanged();
}
}
} = [];
public string Search
{
@@ -112,7 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels
var inSd = path == ModLoader.GetSdModsBasePath();
var modCache = new ModLoader.ModCache();
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, _installedDlcIds);
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, installedDlcIds);
foreach (var mod in modCache.RomfsDirs)
{
@@ -161,8 +144,8 @@ namespace Ryujinx.Ava.UI.ViewModels
.Filter(Filter)
.Bind(out var view).AsObservableList();
_views.Clear();
_views.AddRange(view);
Views.Clear();
Views.AddRange(view);
SelectedMods = new(Views.Where(x => x.Enabled));
+47 -74
View File
@@ -1,6 +1,7 @@
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.OpenAL;
using Ryujinx.Audio.Backends.SDL2;
@@ -41,34 +42,27 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly Dictionary<string, string> _networkInterfaces;
private float _customResolutionScale;
private int _resolutionScale;
private int _graphicsBackendMultithreadingIndex;
private float _volume;
[ObservableProperty]
private bool _isVulkanAvailable = true;
private bool _gameDirectoryChanged;
private bool _autoloadDirectoryChanged;
private readonly List<string> _gpuIds = new();
private int _graphicsBackendIndex;
private readonly List<string> _gpuIds = [];
private int _scalingFilter;
private int _scalingFilterLevel;
private int _customVSyncInterval;
private bool _enableCustomVSyncInterval;
private int _customVSyncIntervalPercentageProxy;
private VSyncMode _vSyncMode;
private long _turboModeMultiplier;
public event Action CloseWindow;
public event Action SaveSettingsEvent;
private int _networkInterfaceIndex;
private int _multiplayerModeIndex;
private string _ldnPassphrase;
private string _LdnServer;
[ObservableProperty]
private bool _matchSystemTime;
private bool _enableGDBStub;
private ushort _gdbStubPort;
private bool _debuggerSuspendOnStart;
public int ResolutionScale
{
@@ -84,15 +78,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public int GraphicsBackendMultithreadingIndex
{
get => _graphicsBackendMultithreadingIndex;
get;
set
{
_graphicsBackendMultithreadingIndex = value;
field = value;
if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
if (field != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
{
Dispatcher.UIThread.InvokeAsync(() =>
ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
"",
"",
LocaleManager.Instance[LocaleKeys.InputDialogOk],
@@ -106,21 +100,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public float CustomResolutionScale
{
get => _customResolutionScale;
get;
set
{
_customResolutionScale = value;
OnPropertyChanged();
}
}
public bool IsVulkanAvailable
{
get => _isVulkanAvailable;
set
{
_isVulkanAvailable = value;
field = value;
OnPropertyChanged();
}
@@ -201,10 +184,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableCustomVSyncInterval
{
get => _enableCustomVSyncInterval;
get;
set
{
_enableCustomVSyncInterval = value;
field = value;
if (_vSyncMode == VSyncMode.Custom && !value)
{
VSyncMode = VSyncMode.Switch;
@@ -213,6 +196,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
VSyncMode = VSyncMode.Custom;
}
OnPropertyChanged();
}
}
@@ -232,23 +216,22 @@ namespace Ryujinx.Ava.UI.ViewModels
}
public bool EnablePptc { get; set; }
public bool EnableLowPowerPptc { get; set; }
public long TurboMultiplier
{
get => _turboModeMultiplier;
get;
set
{
if (_turboModeMultiplier != value)
if (field != value)
{
_turboModeMultiplier = value;
field = value;
OnPropertyChanged();
OnPropertyChanged((nameof(TurboMultiplierPercentageText)));
}
}
}
public string TurboMultiplierPercentageText => $"{TurboMultiplier}%";
public bool EnableInternetAccess { get; set; }
@@ -284,10 +267,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public string LdnPassphrase
{
get => _ldnPassphrase;
get;
set
{
_ldnPassphrase = value;
field = value;
IsInvalidLdnPassphraseVisible = !ValidateLdnPassphrase(value);
OnPropertyChanged();
@@ -308,29 +291,33 @@ namespace Ryujinx.Ava.UI.ViewModels
public int AspectRatio { get; set; }
public int AntiAliasingEffect { get; set; }
public string ScalingFilterLevelText => ScalingFilterLevel.ToString("0");
public int ScalingFilterLevel
{
get => _scalingFilterLevel;
get;
set
{
_scalingFilterLevel = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ScalingFilterLevelText));
}
}
public int OpenglDebugLevel { get; set; }
public int MemoryMode { get; set; }
public int BaseStyleIndex { get; set; }
public int GraphicsBackendIndex
{
get => _graphicsBackendIndex;
get;
set
{
_graphicsBackendIndex = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsVulkanSelected));
}
}
public int ScalingFilter
{
get => _scalingFilter;
@@ -346,26 +333,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public float Volume
{
get => _volume;
get;
set
{
_volume = value;
field = value;
ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
OnPropertyChanged();
}
}
//private DateTimeOffset _currentDate;
//private TimeSpan _currentTime;
public bool MatchSystemTime
{
get => _matchSystemTime;
set
{
_matchSystemTime = value;
ConfigurationState.Instance.System.AudioVolume.Value = field / 100;
OnPropertyChanged();
}
@@ -389,21 +362,21 @@ namespace Ryujinx.Ava.UI.ViewModels
public int NetworkInterfaceIndex
{
get => _networkInterfaceIndex;
get;
set
{
_networkInterfaceIndex = value != -1 ? value : 0;
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[_networkInterfaceIndex]];
field = value != -1 ? value : 0;
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[field]];
}
}
public int MultiplayerModeIndex
{
get => _multiplayerModeIndex;
get;
set
{
_multiplayerModeIndex = value;
ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)_multiplayerModeIndex;
field = value;
ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)field;
}
}
@@ -434,21 +407,21 @@ namespace Ryujinx.Ava.UI.ViewModels
public ushort GDBStubPort
{
get => _gdbStubPort;
get;
set
{
_gdbStubPort = value;
ConfigurationState.Instance.Debug.GdbStubPort.Value = _gdbStubPort;
field = value;
ConfigurationState.Instance.Debug.GdbStubPort.Value = field;
}
}
public bool DebuggerSuspendOnStart
{
get => _debuggerSuspendOnStart;
get;
set
{
_debuggerSuspendOnStart = value;
ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = _debuggerSuspendOnStart;
field = value;
ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = field;
}
}
@@ -2,6 +2,7 @@ using Avalonia.Collections;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
@@ -15,57 +16,24 @@ using Application = Avalonia.Application;
namespace Ryujinx.Ava.UI.ViewModels
{
public record TitleUpdateViewNoUpdateSentinal();
public record TitleUpdateViewNoUpdateSentinal;
public class TitleUpdateViewModel : BaseModel
public partial class TitleUpdateViewModel : BaseModel
{
private ApplicationLibrary ApplicationLibrary { get; }
private ApplicationData ApplicationData { get; }
[ObservableProperty]
private AvaloniaList<TitleUpdateModel> _titleUpdates = [];
[ObservableProperty]
private AvaloniaList<object> _views = [];
[ObservableProperty]
private object _selectedUpdate = new TitleUpdateViewNoUpdateSentinal();
private bool _showBundledContentNotice = false;
public AvaloniaList<TitleUpdateModel> TitleUpdates
{
get => _titleUpdates;
set
{
_titleUpdates = value;
OnPropertyChanged();
}
}
public AvaloniaList<object> Views
{
get => _views;
set
{
_views = value;
OnPropertyChanged();
}
}
public object SelectedUpdate
{
get => _selectedUpdate;
set
{
_selectedUpdate = value;
OnPropertyChanged();
}
}
public bool ShowBundledContentNotice
{
get => _showBundledContentNotice;
set
{
_showBundledContentNotice = value;
OnPropertyChanged();
}
}
[ObservableProperty]
private bool _showBundledContentNotice;
public IStorageProvider StorageProvider;
@@ -1,4 +1,5 @@
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@@ -20,58 +21,38 @@ using Image = SkiaSharp.SKImage;
namespace Ryujinx.Ava.UI.ViewModels
{
internal class UserFirmwareAvatarSelectorViewModel : BaseModel
internal partial class UserFirmwareAvatarSelectorViewModel : BaseModel
{
private static readonly Dictionary<string, byte[]> _avatarStore = new();
[ObservableProperty]
private ObservableCollection<ProfileImageModel> _images;
private Color _backgroundColor = Colors.White;
private int _selectedIndex;
[ObservableProperty]
private Color _backgroundColor = Colors.White;
public UserFirmwareAvatarSelectorViewModel()
{
_images = [];
LoadImagesFromStore();
}
public Color BackgroundColor
{
get => _backgroundColor;
set
PropertyChanged += (_, args) =>
{
_backgroundColor = value;
OnPropertyChanged();
ChangeImageBackground();
}
}
public ObservableCollection<ProfileImageModel> Images
{
get => _images;
set
{
_images = value;
OnPropertyChanged();
}
if (args.PropertyName == nameof(BackgroundColor))
ChangeImageBackground();
};
}
public int SelectedIndex
{
get => _selectedIndex;
get;
set
{
_selectedIndex = value;
field = value;
if (_selectedIndex == -1)
{
SelectedImage = null;
}
else
{
SelectedImage = _images[_selectedIndex].Data;
}
SelectedImage = field == -1
? null
: Images[field].Data;
OnPropertyChanged();
}
@@ -1,18 +1,10 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Ryujinx.Ava.UI.ViewModels
{
internal class UserProfileImageSelectorViewModel : BaseModel
internal partial class UserProfileImageSelectorViewModel : BaseModel
{
[ObservableProperty]
private bool _firmwareFound;
public bool FirmwareFound
{
get => _firmwareFound;
set
{
_firmwareFound = value;
OnPropertyChanged();
}
}
}
}
@@ -1,3 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using DynamicData.Binding;
using Ryujinx.Ava.Common.Locale;
@@ -8,74 +9,41 @@ using System.Collections.ObjectModel;
namespace Ryujinx.Ava.UI.ViewModels
{
public class UserSaveManagerViewModel : BaseModel
public partial class UserSaveManagerViewModel : BaseModel
{
[ObservableProperty]
private int _sortIndex;
[ObservableProperty]
private int _orderIndex;
[ObservableProperty]
private string _search;
[ObservableProperty]
private ObservableCollection<SaveModel> _saves = [];
[ObservableProperty]
private ObservableCollection<SaveModel> _views = [];
private readonly AccountManager _accountManager;
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
public int SortIndex
{
get => _sortIndex;
set
{
_sortIndex = value;
OnPropertyChanged();
Sort();
}
}
public int OrderIndex
{
get => _orderIndex;
set
{
_orderIndex = value;
OnPropertyChanged();
Sort();
}
}
public string Search
{
get => _search;
set
{
_search = value;
OnPropertyChanged();
Sort();
}
}
public ObservableCollection<SaveModel> Saves
{
get => _saves;
set
{
_saves = value;
OnPropertyChanged();
Sort();
}
}
public ObservableCollection<SaveModel> Views
{
get => _views;
set
{
_views = value;
OnPropertyChanged();
}
}
public UserSaveManagerViewModel(AccountManager accountManager)
{
_accountManager = accountManager;
PropertyChanged += (_, evt) =>
{
if (evt.PropertyName is
nameof(SortIndex) or
nameof(OrderIndex) or
nameof(Search) or
nameof(Saves))
{
Sort();
}
};
}
public void Sort()
@@ -85,8 +53,8 @@ namespace Ryujinx.Ava.UI.ViewModels
.Sort(GetComparer())
.Bind(out var view).AsObservableList();
_views.Clear();
_views.AddRange(view);
Views.Clear();
Views.AddRange(view);
OnPropertyChanged(nameof(Views));
}
@@ -94,7 +62,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
if (arg is SaveModel save)
{
return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
return string.IsNullOrWhiteSpace(Search) || save.Title.ToLower().Contains(Search.ToLower());
}
return false;