See merge request ryubing/ryujinx!214
This commit is contained in:
GreemDev
2025-11-11 12:55:36 -06:00
parent 49c70efdd5
commit 6b814fb973
171 changed files with 6011 additions and 6335 deletions

View File

@@ -11,13 +11,17 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class AboutWindowViewModel : BaseModel, IDisposable
{
[ObservableProperty] private Bitmap _gitLabLogo;
[ObservableProperty] private Bitmap _discordLogo;
[ObservableProperty] private string _version;
[ObservableProperty] public partial Bitmap GitLabLogo { get; set; }
public string Developers => "GreemDev, LotP";
[ObservableProperty] public partial Bitmap DiscordLogo { get; set; }
public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
[ObservableProperty] public partial string Version { get; set; }
public static string Developers => "GreemDev, LotP";
public static string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.AboutPageDeveloperListMore,
"gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
public AboutWindowViewModel()
{
@@ -36,7 +40,8 @@ namespace Ryujinx.Ava.UI.ViewModels
private void UpdateLogoTheme(string theme)
{
bool isDarkTheme = theme == "Dark" || (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark);
bool isDarkTheme = theme == "Dark" ||
(theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark);
string themeName = isDarkTheme ? "Dark" : "Light";

View File

@@ -2,6 +2,7 @@ using Avalonia;
using Avalonia.Collections;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models.Amiibo;
using Ryujinx.Ava.UI.Helpers;
@@ -23,7 +24,7 @@ using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.ViewModels
{
public class AmiiboWindowViewModel : BaseModel, IDisposable
public partial class AmiiboWindowViewModel : BaseModel, IDisposable
{
// ReSharper disable once InconsistentNaming
private static bool _cachedUseRandomUuid;
@@ -36,17 +37,13 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly HttpClient _httpClient;
private readonly AmiiboWindow _owner;
private Bitmap _amiiboImage;
private List<AmiiboApi> _amiiboList;
private AvaloniaList<AmiiboApi> _amiibos;
private ObservableCollection<string> _amiiboSeries;
private int _amiiboSelectedIndex;
private int _seriesSelectedIndex;
private bool _enableScanning;
private bool _showAllAmiibo;
private bool _useRandomUuid = _cachedUseRandomUuid;
private string _usage;
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -83,14 +80,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool UseRandomUuid
{
get => _useRandomUuid;
get;
set
{
_cachedUseRandomUuid = _useRandomUuid = value;
_cachedUseRandomUuid = field = value;
OnPropertyChanged();
}
}
} = _cachedUseRandomUuid;
public bool ShowAllAmiibo
{
@@ -154,38 +151,14 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public Bitmap AmiiboImage
{
get => _amiiboImage;
set
{
_amiiboImage = value;
[ObservableProperty]
public partial Bitmap AmiiboImage { get; set; }
OnPropertyChanged();
}
}
[ObservableProperty]
public partial string Usage { get; set; }
public string Usage
{
get => _usage;
set
{
_usage = value;
OnPropertyChanged();
}
}
public bool EnableScanning
{
get => _enableScanning;
set
{
_enableScanning = value;
OnPropertyChanged();
}
}
[ObservableProperty]
public partial bool EnableScanning { get; set; }
public void Scan()
{

View File

@@ -7,14 +7,16 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class DlcSelectViewModel : BaseModel
{
[ObservableProperty] private DownloadableContentModel[] _dlcs;
[ObservableProperty]
public partial DownloadableContentModel[] Dlcs { get; set; }
#nullable enable
[ObservableProperty] private DownloadableContentModel? _selectedDlc;
[ObservableProperty]
public partial DownloadableContentModel? SelectedDlc { get; set; }
#nullable disable
public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary)
{
_dlcs = appLibrary.FindDlcsFor(titleId)
Dlcs = appLibrary.FindDlcsFor(titleId)
.OrderBy(it => it.IsBundled ? 0 : 1)
.ThenBy(it => it.TitleId)
.ToArray();

View File

@@ -19,10 +19,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class DownloadableContentManagerViewModel : BaseModel
{
private readonly ApplicationLibrary _applicationLibrary;
private AvaloniaList<DownloadableContentModel> _downloadableContents = [];
[ObservableProperty] private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = [];
[ObservableProperty] private AvaloniaList<DownloadableContentModel> _views = [];
[ObservableProperty] private bool _showBundledContentNotice = false;
[ObservableProperty]
public partial AvaloniaList<DownloadableContentModel> SelectedDownloadableContents { get; set; } = [];
[ObservableProperty]
public partial AvaloniaList<DownloadableContentModel> Views { get; set; } = [];
[ObservableProperty]
public partial bool ShowBundledContentNotice { get; set; } = false;
private string _search;
private readonly ApplicationData _applicationData;
@@ -30,15 +34,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList<DownloadableContentModel> DownloadableContents
{
get => _downloadableContents;
get;
set
{
_downloadableContents = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UpdateCount));
Sort();
}
}
} = [];
public string Search
{
@@ -51,10 +55,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public string UpdateCount
{
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
}
public string UpdateCount => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
public DownloadableContentManagerViewModel(ApplicationLibrary applicationLibrary, ApplicationData applicationData)
{

View File

@@ -4,55 +4,50 @@ using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.Views.Input;
using System.Drawing;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
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));
}
@@ -60,8 +55,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image;
[ObservableProperty]
public partial SvgImage Image { get; set; }
public InputViewModel ParentModel { get; }
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer)
@@ -75,7 +70,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (args.PropertyName is nameof(Config.UseRainbowLed))
{
if (Config is { UseRainbowLed: true, TurnOffLed: false, EnableLedChanging: true })
Rainbow.Updated += (ref Color color) => ParentModel.SelectedGamepad.SetLed((uint)color.ToArgb());
Rainbow.Updated += (ref color) => ParentModel.SelectedGamepad.SetLed((uint)color.ToArgb());
else
{
Rainbow.Reset();

View File

@@ -48,36 +48,41 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller;
private string _controllerImage;
private int _device;
private object _configViewModel;
private bool _isChangeTrackingActive;
private string _chosenProfile;
[ObservableProperty] private bool _isModified;
[ObservableProperty] private string _profileName;
[ObservableProperty] private bool _notificationIsVisible; // Automatically call the NotificationView property with OnPropertyChanged()
[ObservableProperty] private string _notificationText; // Automatically call the NotificationText property with OnPropertyChanged()
[ObservableProperty]
public partial bool IsModified { get; set; }
[ObservableProperty]
public partial string ProfileName { get; set; }
[ObservableProperty]
public partial bool NotificationIsVisible { get; set; } // Automatically call the NotificationView property with OnPropertyChanged()
[ObservableProperty]
public partial string NotificationText { get; set; } // Automatically call the NotificationText property with OnPropertyChanged()
private bool _isLoaded;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public IGamepadDriver AvaloniaKeyboardDriver { get; }
private IGamepad _selectedGamepad;
public IGamepad SelectedGamepad
{
get => _selectedGamepad;
get;
private set
{
Rainbow.Reset();
_selectedGamepad = value;
field = value;
if (ConfigViewModel is ControllerInputViewModel { Config.UseRainbowLed: true })
Rainbow.Updated += (ref Color color) => _selectedGamepad.SetLed((uint)color.ToArgb());
Rainbow.Updated += (ref Color color) => field.SetLed((uint)color.ToArgb());
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
}
}
public StickVisualizer VisualStick { get; private set; }
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
@@ -99,15 +104,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
public event Action NotifyChangesEvent;
public string ChosenProfile
{
get => _chosenProfile;
get;
set
{
// When you select a profile, the settings from the profile will be applied.
// To save the settings, you still need to click the apply button
_chosenProfile = value;
field = value;
LoadProfile();
OnPropertyChanged();
}
@@ -115,10 +120,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public object ConfigViewModel
{
get => _configViewModel;
get;
set
{
_configViewModel = value;
field = value;
VisualStick.UpdateConfig(value);

View File

@@ -6,49 +6,45 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
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));
}
@@ -56,7 +52,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image;
[ObservableProperty]
public partial SvgImage Image { get; set; }
public readonly InputViewModel ParentModel;

View File

@@ -23,8 +23,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
ParentModel.SelectedGamepad.SetLed(LedColor.ToUInt32());
});
[ObservableProperty] private bool _enableLedChanging;
[ObservableProperty] private Color _ledColor;
[ObservableProperty]
public partial bool EnableLedChanging { get; set; }
[ObservableProperty]
public partial Color LedColor { get; set; }
public string RainbowSpeedText => RainbowSpeed.ToString(CultureInfo.CurrentCulture).Truncate(4, string.Empty);
@@ -41,27 +44,23 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
private bool _turnOffLed;
public bool TurnOffLed
{
get => _turnOffLed;
get;
set
{
_turnOffLed = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}
}
private bool _useRainbowLed;
public bool UseRainbowLed
{
get => _useRainbowLed;
get;
set
{
_useRainbowLed = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}

View File

@@ -4,20 +4,28 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class MotionInputViewModel : BaseModel
{
[ObservableProperty] private int _slot;
[ObservableProperty]
public partial int Slot { get; set; }
[ObservableProperty] private int _altSlot;
[ObservableProperty]
public partial int AltSlot { get; set; }
[ObservableProperty] private string _dsuServerHost;
[ObservableProperty]
public partial string DsuServerHost { get; set; }
[ObservableProperty] private int _dsuServerPort;
[ObservableProperty]
public partial int DsuServerPort { get; set; }
[ObservableProperty] private bool _mirrorInput;
[ObservableProperty]
public partial bool MirrorInput { get; set; }
[ObservableProperty] private int _sensitivity;
[ObservableProperty]
public partial int Sensitivity { get; set; }
[ObservableProperty] private double _gyroDeadzone;
[ObservableProperty]
public partial double GyroDeadzone { get; set; }
[ObservableProperty] private bool _enableCemuHookMotion;
[ObservableProperty]
public partial bool EnableCemuHookMotion { get; set; }
}
}

View File

@@ -4,8 +4,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class RumbleInputViewModel : BaseModel
{
[ObservableProperty] private float _strongRumble;
[ObservableProperty]
public partial float StrongRumble { get; set; }
[ObservableProperty] private float _weakRumble;
[ObservableProperty]
public partial float WeakRumble { get; set; }
}
}

View File

@@ -91,10 +91,8 @@ namespace Ryujinx.Ava.UI.ViewModels
OnPropertyChanged(nameof(VisibleEntries));
}
[ObservableProperty] private bool _isRefreshing;
private bool _onlyShowForOwnedGames;
private bool _onlyShowPublicGames = true;
private bool _onlyShowJoinableGames = true;
[ObservableProperty]
public partial bool IsRefreshing { get; set; }
public async Task RefreshAsync()
{
@@ -109,12 +107,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool OnlyShowForOwnedGames
{
get => _onlyShowForOwnedGames;
get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
_onlyShowForOwnedGames = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
@@ -122,29 +120,29 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool OnlyShowPublicGames
{
get => _onlyShowPublicGames;
get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
_onlyShowPublicGames = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
}
} = true;
public bool OnlyShowJoinableGames
{
get => _onlyShowJoinableGames;
get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
_onlyShowJoinableGames = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
}
} = true;
public void NameSorting(int nameSort = 0)

View File

@@ -64,55 +64,101 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class MainWindowViewModel : BaseModel
{
private const int HotKeyPressDelayMs = 500;
private delegate int LoadContentFromFolderDelegate(List<string> dirs, out int numRemoved);
[ObservableProperty] private ObservableCollectionExtended<ApplicationData> _applications;
[ObservableProperty] private string _aspectRatioStatusText;
[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 _backendText;
[ObservableProperty] private string _shaderCountText;
[ObservableProperty] private bool _showShaderCompilationHint;
[ObservableProperty] private bool _isFullScreen;
[ObservableProperty] private int _progressMaximum;
[ObservableProperty] private int _progressValue;
[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 _isLoadingIndeterminate = true;
[ObservableProperty] private bool _showAll;
[ObservableProperty] private string _lastScannedAmiiboId;
[ObservableProperty] public partial ObservableCollectionExtended<ApplicationData> Applications { get; set; }
[ObservableProperty] public partial string AspectRatioStatusText { get; set; }
[ObservableProperty] public partial string LoadHeading { get; set; }
[ObservableProperty] public partial string CacheLoadStatus { get; set; }
[ObservableProperty] public partial string DockedStatusText { get; set; }
[ObservableProperty] public partial string FifoStatusText { get; set; }
[ObservableProperty] public partial string GameStatusText { get; set; }
[ObservableProperty] public partial string VolumeStatusText { get; set; }
[ObservableProperty] public partial string GpuNameText { get; set; }
[ObservableProperty] public partial string BackendText { get; set; }
[ObservableProperty] public partial string ShaderCountText { get; set; }
[ObservableProperty] public partial bool ShowShaderCompilationHint { get; set; }
[ObservableProperty] public partial bool IsFullScreen { get; set; }
[ObservableProperty] public partial int ProgressMaximum { get; set; }
[ObservableProperty] public partial int ProgressValue { get; set; }
[ObservableProperty] public partial bool ShowMenuAndStatusBar { get; set; } = true;
[ObservableProperty] public partial bool ShowStatusSeparator { get; set; }
[ObservableProperty] public partial Brush ProgressBarForegroundColor { get; set; }
[ObservableProperty] public partial Brush ProgressBarBackgroundColor { get; set; }
#pragma warning disable MVVMTK0042 // Must stay a normal observable field declaration since this is used as an out parameter target
[ObservableProperty] private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
[ObservableProperty] private long _lastFullscreenToggle = Environment.TickCount64;
[ObservableProperty] private bool _showContent = true;
[ObservableProperty] private float _volumeBeforeMute;
[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;
[ObservableProperty] private ApplicationContextMenu _listAppContextMenu;
[ObservableProperty] private ApplicationContextMenu _gridAppContextMenu;
[ObservableProperty] private bool _isRyuLdnEnabled;
[ObservableProperty] private bool _updateAvailable;
#pragma warning restore MVVMTK0042
[ObservableProperty] public partial Brush VSyncModeColor { get; set; }
#nullable enable
[ObservableProperty] public partial byte[]? SelectedIcon { get; set; }
#nullable disable
[ObservableProperty] public partial int StatusBarProgressMaximum { get; set; }
[ObservableProperty] public partial int StatusBarProgressValue { get; set; }
[ObservableProperty] public partial string StatusBarProgressStatusText { get; set; }
[ObservableProperty] public partial bool StatusBarProgressStatusVisible { get; set; }
[ObservableProperty] public partial bool IsPaused { get; set; }
[ObservableProperty] public partial bool IsLoadingIndeterminate { get; set; } = true;
[ObservableProperty] public partial bool ShowAll { get; set; }
[ObservableProperty] public partial string LastScannedAmiiboId { get; set; }
[ObservableProperty]
public partial long LastFullscreenToggle { get; set; } = Environment.TickCount64;
[ObservableProperty] public partial bool ShowContent { get; set; } = true;
[ObservableProperty] public partial float VolumeBeforeMute { get; set; }
[ObservableProperty]
public partial bool AreMimeTypesRegistered { get; set; } = FileAssociationHelper.AreMimeTypesRegistered;
[ObservableProperty] public partial Cursor Cursor { get; set; }
[ObservableProperty] public partial string Title { get; set; }
[ObservableProperty] public partial WindowState WindowState { get; set; }
[ObservableProperty] public partial double WindowWidth { get; set; }
[ObservableProperty] public partial double WindowHeight { get; set; }
[ObservableProperty] public partial bool IsActive { get; set; }
[ObservableProperty] public partial bool IsSubMenuOpen { get; set; }
[ObservableProperty] public partial ApplicationContextMenu ListAppContextMenu { get; set; }
[ObservableProperty] public partial ApplicationContextMenu GridAppContextMenu { get; set; }
[ObservableProperty] public partial bool IsRyuLdnEnabled { get; set; }
[ObservableProperty] public partial bool UpdateAvailable { get; set; }
public static AsyncRelayCommand UpdateCommand { get; } = Commands.Create(async () =>
{
@@ -120,27 +166,17 @@ namespace Ryujinx.Ava.UI.ViewModels
await Updater.BeginUpdateAsync(true);
});
private bool _showTotalTimePlayed;
private bool _showLoadProgress;
private bool _isGameRunning;
private bool _isAmiiboRequested;
private bool _isAmiiboBinRequested;
private string _searchText;
private Timer _searchTimer;
private string _vSyncModeText;
private string _showUiKey = "F4";
private string _pauseKey = "F5";
private string _screenshotKey = "F8";
private float _volume;
private bool _isAppletMenuActive;
private bool _statusBarVisible;
private bool _canUpdate = true;
private ApplicationData _currentApplicationData;
private readonly AutoResetEvent _rendererWaitEvent;
private int _customVSyncInterval;
private int _customVSyncIntervalPercentageProxy;
private ApplicationData _listSelectedApplication;
private ApplicationData _gridSelectedApplication;
// Key is Title ID
/// <summary>
@@ -267,20 +303,20 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CanUpdate
{
get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate();
get => field && EnableNonGameRunningControls && Updater.CanUpdate();
set
{
_canUpdate = value;
field = value;
OnPropertyChanged();
}
}
} = true;
public bool StatusBarVisible
{
get => _statusBarVisible && EnableNonGameRunningControls;
get => field && EnableNonGameRunningControls;
set
{
_statusBarVisible = value;
field = value;
OnPropertyChanged();
}
@@ -312,20 +348,21 @@ 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();
}
@@ -335,10 +372,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowLoadProgress
{
get => _showLoadProgress;
get;
set
{
_showLoadProgress = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowFirmwareStatus));
@@ -360,24 +397,24 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowTotalTimePlayed
{
get => _showTotalTimePlayed && EnableNonGameRunningControls;
get => field && EnableNonGameRunningControls;
set
{
_showTotalTimePlayed = value;
field = value;
OnPropertyChanged();
}
}
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();
@@ -386,14 +423,14 @@ 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();
@@ -422,13 +459,18 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool HasDlc => ApplicationLibrary.HasDlcs(SelectedApplication.Id);
public bool OpenUserSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
public bool OpenUserSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
public bool OpenDeviceSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
public bool OpenDeviceSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
public bool TrimXCIEnabled => XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this));
public bool TrimXCIEnabled =>
XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this));
public bool OpenBcatSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
public bool OpenBcatSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
SelectedApplication.ControlHolder.Value
.BcatDeliveryCacheStorageSize > 0;
public bool ShowCustomVSyncIntervalPicker
=> _isGameRunning && AppHost.Device.VSyncMode == VSyncMode.Custom;
@@ -466,7 +508,6 @@ namespace Ryujinx.Ava.UI.ViewModels
}
set
{
}
}
@@ -492,10 +533,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public string VSyncModeText
{
get => _vSyncModeText;
get;
set
{
_vSyncModeText = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowCustomVSyncIntervalPicker));
@@ -524,10 +565,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsAppletMenuActive
{
get => _isAppletMenuActive && EnableNonGameRunningControls;
get => field && EnableNonGameRunningControls;
set
{
_isAppletMenuActive = value;
field = value;
OnPropertyChanged();
}
@@ -799,7 +840,8 @@ namespace Ryujinx.Ava.UI.ViewModels
#region PrivateMethods
private static SortExpressionComparer<ApplicationData> CreateComparer(bool ascending, Func<ApplicationData, IComparable> selector) =>
private static SortExpressionComparer<ApplicationData> CreateComparer(bool ascending,
Func<ApplicationData, IComparable> selector) =>
ascending
? SortExpressionComparer<ApplicationData>.Ascending(selector)
: SortExpressionComparer<ApplicationData>.Descending(selector);
@@ -808,15 +850,15 @@ namespace Ryujinx.Ava.UI.ViewModels
=> SortMode switch
{
#pragma warning disable IDE0055 // Disable formatting
ApplicationSort.Title => CreateComparer(IsAscending, app => app.Name),
ApplicationSort.Developer => CreateComparer(IsAscending, app => app.Developer),
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
ApplicationSort.Title => CreateComparer(IsAscending, app => app.Name),
ApplicationSort.Developer => CreateComparer(IsAscending, app => app.Developer),
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending),
ApplicationSort.FileType => CreateComparer(IsAscending, app => app.FileExtension),
ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
ApplicationSort.FileType => CreateComparer(IsAscending, app => app.FileExtension),
ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
_ => null,
#pragma warning restore IDE0055
};
@@ -848,7 +890,8 @@ namespace Ryujinx.Ava.UI.ViewModels
CompareInfo compareInfo = CultureInfo.CurrentCulture.CompareInfo;
return compareInfo.IndexOf(app.Name, _searchText, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
return compareInfo.IndexOf(app.Name, _searchText,
CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
}
return false;
@@ -862,21 +905,27 @@ namespace Ryujinx.Ava.UI.ViewModels
if (firmwareVersion == null)
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename));
await ContentDialogHelper.CreateErrorDialog(
LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename));
return;
}
string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString);
string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString);
string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString);
string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString);
SystemVersion currentVersion = ContentManager.GetCurrentFirmwareVersion();
if (currentVersion != null)
{
dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString);
dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString);
}
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
dialogMessage +=
LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
dialogTitle,
@@ -885,7 +934,8 @@ namespace Ryujinx.Ava.UI.ViewModels
LocaleManager.Instance[LocaleKeys.InputDialogNo],
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
UpdateWaitWindow waitingDialog = new(dialogTitle,
LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
if (result == UserResult.Yes)
{
@@ -906,7 +956,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
waitingDialog.Close();
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage, firmwareVersion.VersionString);
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage,
firmwareVersion.VersionString);
await ContentDialogHelper.CreateInfoDialog(
dialogTitle,
@@ -919,7 +971,8 @@ namespace Ryujinx.Ava.UI.ViewModels
// Purge Applet Cache.
DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath,
"0100000000001009", "cache"));
if (miiEditorCacheFolder.Exists)
{
@@ -940,10 +993,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
RefreshFirmwareStatus();
}
})
{
Name = "GUI.FirmwareInstallerThread",
};
}) { Name = "GUI.FirmwareInstallerThread", };
thread.Start();
}
@@ -968,17 +1018,22 @@ namespace Ryujinx.Ava.UI.ViewModels
try
{
string systemDirectory = AppDataManager.KeysDirPath;
if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && Directory.Exists(AppDataManager.KeysDirPathUser))
if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile &&
Directory.Exists(AppDataManager.KeysDirPathUser))
{
systemDirectory = AppDataManager.KeysDirPathUser;
}
string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle);
string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
string dialogTitle =
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle);
string dialogMessage =
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
if (ContentManager.AreKeysAlredyPresent(systemDirectory))
{
dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSubMessage);
dialogMessage +=
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
.DialogKeysInstallerKeysInstallSubMessage);
}
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallConfirmMessage];
@@ -990,7 +1045,8 @@ namespace Ryujinx.Ava.UI.ViewModels
LocaleManager.Instance[LocaleKeys.InputDialogNo],
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]);
UpdateWaitWindow waitingDialog = new(dialogTitle,
LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]);
if (result == UserResult.Yes)
{
@@ -1011,7 +1067,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
waitingDialog.Close();
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSuccessMessage);
string message =
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
.DialogKeysInstallerKeysInstallSuccessMessage);
await ContentDialogHelper.CreateInfoDialog(
dialogTitle,
@@ -1032,7 +1090,8 @@ namespace Ryujinx.Ava.UI.ViewModels
string message = ex.Message;
if (ex is FormatException)
{
message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename);
message = LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename);
}
await ContentDialogHelper.CreateErrorDialog(message);
@@ -1042,10 +1101,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
VirtualFileSystem.ReloadKeySet();
}
})
{
Name = "GUI.KeysInstallerThread",
};
}) { Name = "GUI.KeysInstallerThread", };
thread.Start();
}
@@ -1064,6 +1120,7 @@ namespace Ryujinx.Ava.UI.ViewModels
await ContentDialogHelper.CreateErrorDialog(ex.Message);
}
}
private void ProgressHandler<T>(T state, int current, int total) where T : Enum
{
Dispatcher.UIThread.Post(() =>
@@ -1083,7 +1140,8 @@ namespace Ryujinx.Ava.UI.ViewModels
IsLoadingIndeterminate = false;
break;
case LoadState.Loaded:
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name);
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading,
_currentApplicationData.Name);
IsLoadingIndeterminate = true;
CacheLoadStatus = string.Empty;
break;
@@ -1104,7 +1162,8 @@ namespace Ryujinx.Ava.UI.ViewModels
IsLoadingIndeterminate = false;
break;
case ShaderCacheLoadingState.Loaded:
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name);
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading,
_currentApplicationData.Name);
IsLoadingIndeterminate = true;
CacheLoadStatus = string.Empty;
break;
@@ -1204,12 +1263,12 @@ namespace Ryujinx.Ava.UI.ViewModels
_rendererWaitEvent.Set();
}
private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle)
private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey,
LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle)
{
Optional<IReadOnlyList<IStorageFolder>> result = await StorageProvider.OpenMultiFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[dirSelectDialogTitle]
});
Optional<IReadOnlyList<IStorageFolder>> result =
await StorageProvider.OpenMultiFolderPickerAsync(
new FolderPickerOpenOptions { Title = LocaleManager.Instance[dirSelectDialogTitle] });
if (result.TryGet(out IReadOnlyList<IStorageFolder> foldersToLoad))
{
@@ -1224,7 +1283,8 @@ namespace Ryujinx.Ava.UI.ViewModels
await Dispatcher.UIThread.InvokeAsync(async () =>
{
await ContentDialogHelper.ShowTextDialog(
LocaleManager.Instance[numAdded > 0 || numRemoved > 0 ? LocaleKeys.RyujinxConfirm : LocaleKeys.RyujinxInfo],
LocaleManager.Instance[
numAdded > 0 || numRemoved > 0 ? LocaleKeys.RyujinxConfirm : LocaleKeys.RyujinxInfo],
msg,
string.Empty,
string.Empty,
@@ -1253,17 +1313,21 @@ namespace Ryujinx.Ava.UI.ViewModels
public void LoadConfigurableHotKeys()
{
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out Avalonia.Input.Key showUiKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI,
out Avalonia.Input.Key showUiKey))
{
ShowUiKey = new KeyGesture(showUiKey);
}
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out Avalonia.Input.Key screenshotKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey(
(Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot,
out Avalonia.Input.Key screenshotKey))
{
ScreenshotKey = new KeyGesture(screenshotKey);
}
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out Avalonia.Input.Key pauseKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause,
out Avalonia.Input.Key pauseKey))
{
PauseKey = new KeyGesture(pauseKey);
}
@@ -1283,7 +1347,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public void SetGridMode() => Glyph = Glyph.Grid;
public void SetAspectRatio(AspectRatio aspectRatio) => ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio;
public void SetAspectRatio(AspectRatio aspectRatio) =>
ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio;
public async Task InstallFirmwareFromFile()
{
@@ -1375,7 +1440,8 @@ namespace Ryujinx.Ava.UI.ViewModels
}
catch (Exception ex)
{
Logger.Error?.Print(LogClass.Application, $"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot");
Logger.Error?.Print(LogClass.Application,
$"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot");
return;
}
@@ -1448,7 +1514,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task ManageProfiles()
{
await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem,
LibHacHorizonManager.RyujinxClient);
}
public void SimulateWakeUpMessage()
@@ -1525,7 +1592,8 @@ namespace Ryujinx.Ava.UI.ViewModels
}
else
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]);
await ContentDialogHelper.CreateErrorDialog(
LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]);
}
}
}
@@ -1550,17 +1618,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFolder()
{
Optional<IStorageFolder> result = await StorageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.LoadUnpackedGameFromFolderDialogTitle]
});
Optional<IStorageFolder> result = await StorageProvider.OpenSingleFolderPickerAsync(
new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.LoadUnpackedGameFromFolderDialogTitle]
});
if (result.TryGet(out IStorageFolder value))
{
ApplicationData applicationData = new()
{
Name = Path.GetFileNameWithoutExtension(value.Path.LocalPath),
Path = value.Path.LocalPath,
Name = Path.GetFileNameWithoutExtension(value.Path.LocalPath), Path = value.Path.LocalPath,
};
await LoadApplication(applicationData);
@@ -1570,29 +1638,34 @@ namespace Ryujinx.Ava.UI.ViewModels
public static bool InitializeUserConfig(ApplicationData application)
{
// Code where conditions will be met before loading the user configuration (Global Config)
string backendThreadingInit = Program.BackendThreadingArg ?? ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString();
string backendThreadingInit = Program.BackendThreadingArg ??
ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString();
// If a configuration is found in the "/games/xxxxxxxxxxxxxx" folder, the program will load the user setting.
string idGame = application.IdBaseString;
if (ConfigurationFileFormat.TryLoad(Program.GetDirGameUserConfig(idGame), out ConfigurationFileFormat configurationFileFormat))
if (ConfigurationFileFormat.TryLoad(Program.GetDirGameUserConfig(idGame),
out ConfigurationFileFormat configurationFileFormat))
{
// Loads the user configuration, having previously changed the global configuration to the user configuration
ConfigurationState.Instance.Load(configurationFileFormat, Program.GetDirGameUserConfig(idGame, true), idGame);
ConfigurationState.Instance.Load(configurationFileFormat, Program.GetDirGameUserConfig(idGame, true),
idGame);
if (ConfigurationFileFormat.TryLoad(Program.GlobalConfigurationPath, out ConfigurationFileFormat configurationFileFormatExtra))
if (ConfigurationFileFormat.TryLoad(Program.GlobalConfigurationPath,
out ConfigurationFileFormat configurationFileFormatExtra))
{
//This is where the global configuration will be stored.
//This allows you to change the global configuration settings during the game (for example, the global input setting)
ConfigurationState.InstanceExtra.Load(configurationFileFormatExtra, Program.GlobalConfigurationPath);
ConfigurationState.InstanceExtra.Load(configurationFileFormatExtra,
Program.GlobalConfigurationPath);
}
}
// Code where conditions will be executed after loading user configuration
if (ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() != backendThreadingInit)
{
Rebooter.RebootAppWithGame(application.Path,
Rebooter.RebootAppWithGame(application.Path,
[
"--bt",
"--bt",
ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString()
]);
@@ -1602,7 +1675,8 @@ namespace Ryujinx.Ava.UI.ViewModels
return false;
}
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct<ApplicationControlProperty>? customNacpData = null)
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false,
BlitStruct<ApplicationControlProperty>? customNacpData = null)
{
if (InitializeUserConfig(application))
return;
@@ -1626,7 +1700,8 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.RestartTime();
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path, ConfigurationState.Instance.System.Language, application.Id);
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
ConfigurationState.Instance.System.Language, application.Id);
PrepareLoadScreen();
@@ -1664,7 +1739,6 @@ namespace Ryujinx.Ava.UI.ViewModels
Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" };
gameThread.Start();
}
public void SwitchToRenderer(bool startFullscreen) =>
@@ -1696,7 +1770,8 @@ namespace Ryujinx.Ava.UI.ViewModels
if (version != null)
{
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, version.VersionString);
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion,
version.VersionString);
hasApplet = version.Major > 3;
}
@@ -1749,7 +1824,7 @@ namespace Ryujinx.Ava.UI.ViewModels
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning)
{
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId ?? string.Empty, titleId);
await StyleableAppWindow.ShowAsync(window);
@@ -1762,22 +1837,24 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
}
public async Task OpenBinFile()
{
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
{
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
FileTypeFilter = new List<FilePickerFileType>
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(
new FilePickerOpenOptions
{
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
FileTypeFilter = new List<FilePickerFileType>
{
Patterns = ["*.bin"],
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
{
Patterns = ["*.bin"],
}
}
}
});
});
if (result.HasValue)
{
AppHost.Device.System.ScanAmiiboFromBin(result.Value.Path.LocalPath);
@@ -1828,9 +1905,11 @@ namespace Ryujinx.Ava.UI.ViewModels
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
{
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage];
string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
string secondaryMessage =
LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
UserResult result =
await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
if (result == UserResult.Yes)
{
@@ -1843,9 +1922,11 @@ namespace Ryujinx.Ava.UI.ViewModels
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
{
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage];
string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
string secondaryMessage =
LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
UserResult result =
await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
if (result == UserResult.Yes)
{
@@ -1900,7 +1981,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void ProcessTrimResult(String filename, XCIFileTrimmer.OperationOutcome operationOutcome)
{
string notifyUser = operationOutcome.ToLocalisedText();
string notifyUser = operationOutcome.LocalizedText;
if (notifyUser != null)
{
@@ -1934,7 +2015,8 @@ namespace Ryujinx.Ava.UI.ViewModels
double savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
double currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
double cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.TrimXCIFileDialogPrimaryText],
@@ -1950,7 +2032,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
Dispatcher.UIThread.Post(() =>
{
StatusBarProgressStatusText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarXCIFileTrimming, Path.GetFileName(filename));
StatusBarProgressStatusText =
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarXCIFileTrimming,
Path.GetFileName(filename));
StatusBarProgressStatusVisible = true;
StatusBarProgressMaximum = 1;
StatusBarProgressValue = 0;
@@ -1975,11 +2059,7 @@ namespace Ryujinx.Ava.UI.ViewModels
StatusBarVisible = false;
});
}
})
{
Name = "GUI.XCIFileTrimmerThread",
IsBackground = true,
};
}) { Name = "GUI.XCIFileTrimmerThread", IsBackground = true, };
XCIFileTrimThread.Start();
}
}
@@ -2041,7 +2121,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public static RelayCommand<MainWindowViewModel> OpenUserSaveDirectory { get; } =
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
viewModel =>
OpenSaveDirectory(viewModel, SaveDataType.Account, viewModel.AccountManager.LastOpenedUser.UserId.ToLibHac())
OpenSaveDirectory(viewModel, SaveDataType.Account,
viewModel.AccountManager.LastOpenedUser.UserId.ToLibHac())
);
public static RelayCommand<MainWindowViewModel> OpenDeviceSaveDirectory { get; } =
@@ -2097,7 +2178,8 @@ namespace Ryujinx.Ava.UI.ViewModels
viewModel =>
{
string modsBasePath = ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
string titleModsPath =
ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
OpenHelper.OpenFolder(titleModsPath);
});
@@ -2107,7 +2189,8 @@ namespace Ryujinx.Ava.UI.ViewModels
viewModel =>
{
string sdModsBasePath = ModLoader.GetSdModsBasePath();
string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
string titleModsPath =
ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
OpenHelper.OpenFolder(titleModsPath);
});

View File

@@ -24,9 +24,11 @@ namespace Ryujinx.Ava.UI.ViewModels
{
private readonly string _modJsonPath;
private AvaloniaList<ModModel> _mods = [];
[ObservableProperty] private AvaloniaList<ModModel> _views = [];
[ObservableProperty] private AvaloniaList<ModModel> _selectedMods = [];
[ObservableProperty]
public partial AvaloniaList<ModModel> Views { get; set; } = [];
[ObservableProperty]
public partial AvaloniaList<ModModel> SelectedMods { get; set; } = [];
private string _search;
private readonly ulong _applicationId;
@@ -37,15 +39,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList<ModModel> Mods
{
get => _mods;
get;
set
{
_mods = value;
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ModCount));
Sort();
}
}
} = [];
public string Search
{
@@ -58,10 +60,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public string ModCount
{
get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
}
public string ModCount => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
public ModManagerViewModel(ulong applicationId, ulong applicationIdBase, ApplicationLibrary appLibrary)
{

View File

@@ -7,8 +7,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class ProfileSelectorDialogViewModel : BaseModel
{
[ObservableProperty] private UserId _selectedUserId;
[ObservableProperty]
public partial UserId SelectedUserId { get; set; }
[ObservableProperty] private ObservableCollection<BaseModel> _profiles = [];
[ObservableProperty]
public partial ObservableCollection<BaseModel> Profiles { get; set; } = [];
}
}

View File

@@ -15,9 +15,13 @@ namespace Ryujinx.Ava.UI.ViewModels
_baseViewModel = settingsVm;
}
[ObservableProperty] private bool _xc2MenuSoftlockFix = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix;
[ObservableProperty] private bool _nifmDisableIsAnyInternetRequestAccepted = ConfigurationState.Instance.Hacks.DisableNifmIsAnyInternetRequestAccepted;
[ObservableProperty]
public partial bool Xc2MenuSoftlockFix { get; set; } = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix;
[ObservableProperty]
public partial bool NifmDisableIsAnyInternetRequestAccepted { get; set; } = ConfigurationState.Instance.Hacks.DisableNifmIsAnyInternetRequestAccepted;
public static string Xc2MenuFixTooltip { get; } = Lambda.String(sb =>
{
sb.AppendLine(

View File

@@ -19,7 +19,6 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
@@ -46,47 +45,49 @@ 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;
[ObservableProperty] private bool _gameListNeedsRefresh;
[ObservableProperty]
public partial bool IsVulkanAvailable { get; set; } = true;
[ObservableProperty]
public partial bool GameListNeedsRefresh { get; set; }
private readonly List<string> _gpuIds = [];
public bool _useInputGlobalConfig;
private int _graphicsBackendIndex;
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;
public event Action<bool> LocalGlobalInputSwitchEvent;
private int _networkInterfaceIndex;
private int _multiplayerModeIndex;
private string _ldnPassphrase;
[ObservableProperty] private string _ldnServer;
private bool _enableGDBStub;
private ushort _gdbStubPort;
private bool _debuggerSuspendOnStart;
public SettingsHacksViewModel DirtyHacks { get; }
private readonly bool _isGameRunning;
private readonly Bitmap _gameIcon;
private readonly string _gameTitle;
private readonly string _gamePath;
private readonly string _gameId;
public bool IsGameRunning => _isGameRunning;
public Bitmap GameIcon => _gameIcon;
public string GamePath => _gamePath;
public string GameTitle => _gameTitle;
public string GameId => _gameId;
public bool IsGameRunning
{
get;
}
public Bitmap GameIcon
{
get;
}
public string GamePath
{
get;
}
public string GameTitle
{
get;
}
public string GameId
{
get;
}
public bool IsGameTitleNotNull => !string.IsNullOrEmpty(GameTitle);
public double PanelOpacity => IsGameTitleNotNull ? 0.5 : 1;
@@ -104,17 +105,18 @@ 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],
string.Empty,
string.Empty,
ContentDialogHelper.CreateInfoDialog(
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
string.Empty,
string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogOk],
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle])
);
@@ -126,10 +128,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public float CustomResolutionScale
{
get => _customResolutionScale;
get;
set
{
_customResolutionScale = MathF.Round(value, 1);
field = MathF.Round(value, 1);
OnPropertyChanged();
}
@@ -152,12 +154,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public int FocusLostActionType { get; set; }
public bool UseGlobalInputConfig
{
get => _useInputGlobalConfig;
{
get;
set
{
_useInputGlobalConfig = value;
LocalGlobalInputSwitchEvent?.Invoke(_useInputGlobalConfig);
field = value;
LocalGlobalInputSwitchEvent?.Invoke(field);
OnPropertyChanged(nameof(InputPanelOpacity));
OnPropertyChanged();
}
@@ -196,10 +198,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;
@@ -233,12 +235,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public long TurboMultiplier
{
get => _turboModeMultiplier;
get;
set
{
if (_turboModeMultiplier != value)
if (field != value)
{
_turboModeMultiplier = value;
field = value;
OnPropertyChanged();
OnPropertyChanged((nameof(TurboMultiplierPercentageText)));
@@ -285,10 +287,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public string LdnPassphrase
{
get => _ldnPassphrase;
get;
set
{
_ldnPassphrase = value;
field = value;
IsInvalidLdnPassphraseVisible = !ValidateLdnPassphrase(value);
OnPropertyChanged();
@@ -304,29 +306,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;
@@ -342,12 +348,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public float Volume
{
get => _volume;
get;
set
{
_volume = value;
field = value;
ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
ConfigurationState.Instance.System.AudioVolume.Value = field / 100;
OnPropertyChanged();
}
@@ -373,19 +379,19 @@ namespace Ryujinx.Ava.UI.ViewModels
public int NetworkInterfaceIndex
{
get => _networkInterfaceIndex;
get;
set
{
_networkInterfaceIndex = value != -1 ? value : 0;
field = value != -1 ? value : 0;
}
}
public int MultiplayerModeIndex
{
get => _multiplayerModeIndex;
get;
set
{
_multiplayerModeIndex = value;
field = value;
}
}
@@ -393,31 +399,31 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableGdbStub
{
get => _enableGDBStub;
get;
set
{
_enableGDBStub = value;
ConfigurationState.Instance.Debug.EnableGdbStub.Value = _enableGDBStub;
field = value;
ConfigurationState.Instance.Debug.EnableGdbStub.Value = field;
}
}
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;
}
}
@@ -450,13 +456,13 @@ namespace Ryujinx.Ava.UI.ViewModels
if (gameIconData is { Length: > 0 })
{
using MemoryStream ms = new(gameIconData);
_gameIcon = new Bitmap(ms);
GameIcon = new Bitmap(ms);
}
_isGameRunning = gameRunning;
_gamePath = gamePath;
_gameTitle = gameName;
_gameId = gameId;
IsGameRunning = gameRunning;
GamePath = gamePath;
GameTitle = gameName;
GameId = gameId;
if (customConfig) // During the game. If there is no user config, then load the global config window
{
@@ -717,7 +723,6 @@ namespace Ryujinx.Ava.UI.ViewModels
MultiplayerModeIndex = (int)config.Multiplayer.Mode.Value;
DisableP2P = config.Multiplayer.DisableP2p;
LdnPassphrase = config.Multiplayer.LdnPassphrase;
LdnServer = config.Multiplayer.LdnServer;
// Debug
EnableGdbStub = config.Debug.EnableGdbStub.Value;
@@ -842,7 +847,6 @@ namespace Ryujinx.Ava.UI.ViewModels
config.Multiplayer.Mode.Value = (MultiplayerMode)MultiplayerModeIndex;
config.Multiplayer.DisableP2p.Value = DisableP2P;
config.Multiplayer.LdnPassphrase.Value = LdnPassphrase;
config.Multiplayer.LdnServer.Value = LdnServer;
// Debug
config.Debug.EnableGdbStub.Value = EnableGdbStub;

View File

@@ -21,10 +21,17 @@ namespace Ryujinx.Ava.UI.ViewModels
private ApplicationLibrary ApplicationLibrary { get; }
private ApplicationData ApplicationData { get; }
[ObservableProperty] private AvaloniaList<TitleUpdateModel> _titleUpdates = [];
[ObservableProperty] private AvaloniaList<object> _views = [];
[ObservableProperty] private object _selectedUpdate = new TitleUpdateViewModelNoUpdate();
[ObservableProperty] private bool _showBundledContentNotice;
[ObservableProperty]
public partial AvaloniaList<TitleUpdateModel> TitleUpdates { get; set; } = [];
[ObservableProperty]
public partial AvaloniaList<object> Views { get; set; } = [];
[ObservableProperty]
public partial object SelectedUpdate { get; set; } = new TitleUpdateViewModelNoUpdate();
[ObservableProperty]
public partial bool ShowBundledContentNotice { get; set; }
private readonly IStorageProvider _storageProvider;

View File

@@ -25,14 +25,15 @@ namespace Ryujinx.Ava.UI.ViewModels
{
private static readonly Dictionary<string, byte[]> _avatarStore = new();
[ObservableProperty] private ObservableCollection<ProfileImageModel> _images;
[ObservableProperty] private Color _backgroundColor = Colors.White;
[ObservableProperty]
public partial ObservableCollection<ProfileImageModel> Images { get; set; }
private int _selectedIndex;
[ObservableProperty]
public partial Color BackgroundColor { get; set; } = Colors.White;
public UserFirmwareAvatarSelectorViewModel()
{
_images = [];
Images = [];
LoadImagesFromStore();
PropertyChanged += (_, args) =>
@@ -44,21 +45,17 @@ namespace Ryujinx.Ava.UI.ViewModels
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();
OnPropertyChanged(nameof(SelectedImage));
}
}

View File

@@ -4,6 +4,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class UserProfileImageSelectorViewModel : BaseModel
{
[ObservableProperty] private bool _firmwareFound;
[ObservableProperty]
public partial bool FirmwareFound { get; set; }
}
}

View File

@@ -10,11 +10,21 @@ namespace Ryujinx.Ava.UI.ViewModels
{
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 = [];
[ObservableProperty]
public partial int SortIndex { get; set; }
[ObservableProperty]
public partial int OrderIndex { get; set; }
[ObservableProperty]
public partial string Search { get; set; }
[ObservableProperty]
public partial ObservableCollection<SaveModel> Saves { get; set; } = [];
[ObservableProperty]
public partial ObservableCollection<SaveModel> Views { get; set; } = [];
private readonly AccountManager _accountManager;
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);

View File

@@ -18,7 +18,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public class XciTrimmerViewModel : BaseModel
{
private const long _bytesPerMB = 1024 * 1024;
private const long BytesPerMb = 1024 * 1024;
private enum ProcessingMode
{
Trimming,
@@ -44,7 +45,6 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _search;
private ProcessingMode _processingMode;
private SortField _sortField = SortField.Name;
private bool _sortAscending = true;
public XciTrimmerViewModel(MainWindowViewModel mainWindowViewModel)
{
@@ -472,15 +472,16 @@ namespace Ryujinx.Ava.UI.ViewModels
};
}
}
public bool SortingAscending
{
get => _sortAscending;
get;
set
{
_sortAscending = value;
field = value;
SortingChanged();
}
}
} = true;
public bool IsSortedByName
{
@@ -516,7 +517,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
get
{
return string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerSavingsMb], AllXCIFiles.Sum(xci => xci.PotentialSavingsB / _bytesPerMB));
return string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerSavingsMb], AllXCIFiles.Sum(xci => xci.PotentialSavingsB / BytesPerMb));
}
}
@@ -524,7 +525,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
get
{
return string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerSavingsMb], AllXCIFiles.Sum(xci => xci.CurrentSavingsB / _bytesPerMB));
return string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerSavingsMb], AllXCIFiles.Sum(xci => xci.CurrentSavingsB / BytesPerMb));
}
}