Migrate System to SettingsSystemViewModel

This commit is contained in:
Isaac Marovitz 2024-04-19 17:05:07 -04:00
parent 65ec957c4c
commit 9b6241985f
No known key found for this signature in database
GPG key ID: 97250B2B09A132E1
5 changed files with 244 additions and 173 deletions

View file

@ -0,0 +1,226 @@
using Avalonia.Collections;
using Avalonia.Threading;
using LibHac.Tools.FsSystem;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Configuration.System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.ViewModels.Settings
{
public class SettingsSystemViewModel : BaseModel
{
public event Action DirtyEvent;
private readonly List<string> _validTzRegions = new();
private readonly VirtualFileSystem _virtualFileSystem;
private readonly ContentManager _contentManager;
private TimeZoneContentManager _timeZoneContentManager;
private int _region;
public int Region
{
get => _region;
set
{
_region = value;
DirtyEvent?.Invoke();
}
}
private int _language;
public int Language
{
get => _language;
set
{
_language = value;
DirtyEvent?.Invoke();
}
}
private string _timeZone;
public string TimeZone
{
get => _timeZone;
set
{
_timeZone = value;
OnPropertyChanged();
DirtyEvent?.Invoke();
}
}
private DateTimeOffset _currentDate;
public DateTimeOffset CurrentDate
{
get => _currentDate;
set
{
_currentDate = value;
DirtyEvent?.Invoke();
}
}
private TimeSpan _currentTime;
public TimeSpan CurrentTime
{
get => _currentTime;
set
{
_currentTime = value;
DirtyEvent?.Invoke();
}
}
private bool _enableVsync;
public bool EnableVsync
{
get => _enableVsync;
set
{
_enableVsync = value;
DirtyEvent?.Invoke();
}
}
private bool _enableFsIntegrityChecks;
public bool EnableFsIntegrityChecks
{
get => _enableFsIntegrityChecks;
set
{
_enableFsIntegrityChecks = value;
DirtyEvent?.Invoke();
}
}
private bool _ignoreMissingServices;
public bool IgnoreMissingServices
{
get => _ignoreMissingServices;
set
{
_ignoreMissingServices = value;
DirtyEvent?.Invoke();
}
}
private bool _expandedDramSize;
public bool ExpandDramSize
{
get => _expandedDramSize;
set
{
_expandedDramSize = value;
DirtyEvent?.Invoke();
}
}
internal AvaloniaList<TimeZone> TimeZones { get; set; }
public SettingsSystemViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
{
_virtualFileSystem = virtualFileSystem;
_contentManager = contentManager;
ConfigurationState config = ConfigurationState.Instance;
TimeZones = new();
if (Program.PreviewerDetached)
{
Task.Run(LoadTimeZones);
}
Region = (int)config.System.Region.Value;
Language = (int)config.System.Language.Value;
TimeZone = config.System.TimeZone;
DateTime currentDateTime = DateTime.Now;
CurrentDate = currentDateTime.Date;
CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset));
EnableVsync = config.Graphics.EnableVsync;
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
ExpandDramSize = config.System.ExpandRam;
IgnoreMissingServices = config.System.IgnoreMissingServices;
}
public async Task LoadTimeZones()
{
_timeZoneContentManager = new TimeZoneContentManager();
_timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None);
foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets())
{
int hours = Math.DivRem(offset, 3600, out int seconds);
int minutes = Math.Abs(seconds) / 60;
string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr;
await Dispatcher.UIThread.InvokeAsync(() =>
{
TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2));
_validTzRegions.Add(location);
});
}
}
public void ValidateAndSetTimeZone(string location)
{
if (_validTzRegions.Contains(location))
{
TimeZone = location;
}
}
public bool CheckIfModified(ConfigurationState config)
{
bool isDirty = false;
isDirty |= config.System.Region.Value != (Region)Region;
isDirty |= config.System.Language.Value != (Language)Language;
if (_validTzRegions.Contains(TimeZone))
{
isDirty |= config.System.TimeZone.Value != TimeZone;
}
// SystemTimeOffset will always have changed, so we don't check it here
isDirty |= config.Graphics.EnableVsync.Value != EnableVsync;
isDirty |= config.System.EnableFsIntegrityChecks.Value != EnableFsIntegrityChecks;
isDirty |= config.System.ExpandRam.Value != ExpandDramSize;
isDirty |= config.System.IgnoreMissingServices.Value != IgnoreMissingServices;
return isDirty;
}
public void Save(ConfigurationState config)
{
config.System.Region.Value = (Region)Region;
config.System.Language.Value = (Language)Language;
if (_validTzRegions.Contains(TimeZone))
{
config.System.TimeZone.Value = TimeZone;
}
config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
config.Graphics.EnableVsync.Value = EnableVsync;
config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
config.System.ExpandRam.Value = ExpandDramSize;
config.System.IgnoreMissingServices.Value = IgnoreMissingServices;
}
}
}

View file

@ -1,33 +1,16 @@
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Threading;
using LibHac.Tools.FsSystem;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.UI.Common.Configuration; using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Configuration.System;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.ViewModels.Settings namespace Ryujinx.Ava.UI.ViewModels.Settings
{ {
public class SettingsViewModel : BaseModel public class SettingsViewModel : BaseModel
{ {
private readonly VirtualFileSystem _virtualFileSystem;
private readonly ContentManager _contentManager;
private TimeZoneContentManager _timeZoneContentManager;
private readonly List<string> _validTzRegions;
private bool _directoryChanged; private bool _directoryChanged;
private bool _isModified; private bool _isModified;
public bool IsModified public bool IsModified
@ -101,53 +84,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
} }
} }
private bool _enableVsync;
public bool EnableVsync
{
get => _enableVsync;
set
{
_enableVsync = value;
CheckIfModified();
}
}
private bool _enableFsIntegrityChecks;
public bool EnableFsIntegrityChecks
{
get => _enableFsIntegrityChecks;
set
{
_enableFsIntegrityChecks = value;
CheckIfModified();
}
}
private bool _ignoreMissingServices;
public bool IgnoreMissingServices
{
get => _ignoreMissingServices;
set
{
_ignoreMissingServices = value;
CheckIfModified();
}
}
private bool _expandedDramSize;
public bool ExpandDramSize
{
get => _expandedDramSize;
set
{
_expandedDramSize = value;
CheckIfModified();
}
}
public string TimeZone { get; set; }
public int Language { get; set; }
public int Region { get; set; }
public int BaseStyleIndex { get; set; } public int BaseStyleIndex { get; set; }
private readonly SettingsAudioViewModel _audioViewModel; private readonly SettingsAudioViewModel _audioViewModel;
@ -157,27 +93,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
private readonly SettingsInputViewModel _inputViewModel; private readonly SettingsInputViewModel _inputViewModel;
private readonly SettingsLoggingViewModel _loggingViewModel; private readonly SettingsLoggingViewModel _loggingViewModel;
private readonly SettingsNetworkViewModel _networkViewModel; private readonly SettingsNetworkViewModel _networkViewModel;
private readonly SettingsSystemViewModel _systemViewModel;
public DateTimeOffset CurrentDate { get; set; }
public TimeSpan CurrentTime { get; set; }
internal AvaloniaList<TimeZone> TimeZones { get; set; }
public AvaloniaList<string> GameDirectories { get; set; } public AvaloniaList<string> GameDirectories { get; set; }
public SettingsViewModel( public SettingsViewModel(
VirtualFileSystem virtualFileSystem,
ContentManager contentManager,
SettingsAudioViewModel audioViewModel, SettingsAudioViewModel audioViewModel,
SettingsCpuViewModel cpuViewModel, SettingsCpuViewModel cpuViewModel,
SettingsGraphicsViewModel graphicsViewModel, SettingsGraphicsViewModel graphicsViewModel,
SettingsHotkeysViewModel hotkeysViewModel, SettingsHotkeysViewModel hotkeysViewModel,
SettingsInputViewModel inputViewModel, SettingsInputViewModel inputViewModel,
SettingsLoggingViewModel loggingViewModel, SettingsLoggingViewModel loggingViewModel,
SettingsNetworkViewModel networkViewModel) : this() SettingsNetworkViewModel networkViewModel,
SettingsSystemViewModel systemViewModel) : this()
{ {
_virtualFileSystem = virtualFileSystem;
_contentManager = contentManager;
_audioViewModel = audioViewModel; _audioViewModel = audioViewModel;
_cpuViewModel = cpuViewModel; _cpuViewModel = cpuViewModel;
_graphicsViewModel = graphicsViewModel; _graphicsViewModel = graphicsViewModel;
@ -185,6 +114,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
_inputViewModel = inputViewModel; _inputViewModel = inputViewModel;
_loggingViewModel = loggingViewModel; _loggingViewModel = loggingViewModel;
_networkViewModel = networkViewModel; _networkViewModel = networkViewModel;
_systemViewModel = systemViewModel;
_audioViewModel.DirtyEvent += CheckIfModified; _audioViewModel.DirtyEvent += CheckIfModified;
_cpuViewModel.DirtyEvent += CheckIfModified; _cpuViewModel.DirtyEvent += CheckIfModified;
@ -193,18 +123,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
_inputViewModel.DirtyEvent += CheckIfModified; _inputViewModel.DirtyEvent += CheckIfModified;
_loggingViewModel.DirtyEvent += CheckIfModified; _loggingViewModel.DirtyEvent += CheckIfModified;
_networkViewModel.DirtyEvent += CheckIfModified; _networkViewModel.DirtyEvent += CheckIfModified;
_systemViewModel.DirtyEvent += CheckIfModified;
if (Program.PreviewerDetached)
{
Task.Run(LoadTimeZones);
}
} }
public SettingsViewModel() public SettingsViewModel()
{ {
GameDirectories = new AvaloniaList<string>(); GameDirectories = new AvaloniaList<string>();
TimeZones = new AvaloniaList<TimeZone>();
_validTzRegions = new List<string>();
if (Program.PreviewerDetached) if (Program.PreviewerDetached)
{ {
@ -227,24 +151,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
isDirty |= config.UI.BaseStyle.Value != (BaseStyleIndex == 0 ? "Light" : "Dark"); isDirty |= config.UI.BaseStyle.Value != (BaseStyleIndex == 0 ? "Light" : "Dark");
// Keyboard Hotkeys
// isDirty |= config.Hid.Hotkeys.Value != KeyboardHotkey.GetConfig();
// System
isDirty |= config.System.Region.Value != (Region)Region;
isDirty |= config.System.Language.Value != (Language)Language;
if (_validTzRegions.Contains(TimeZone))
{
isDirty |= config.System.TimeZone.Value != TimeZone;
}
// isDirty |= config.System.SystemTimeOffset.Value != Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
isDirty |= config.Graphics.EnableVsync.Value != EnableVsync;
isDirty |= config.System.EnableFsIntegrityChecks.Value != EnableFsIntegrityChecks;
isDirty |= config.System.ExpandRam.Value != ExpandDramSize;
isDirty |= config.System.IgnoreMissingServices.Value != IgnoreMissingServices;
isDirty |= _audioViewModel?.CheckIfModified(config) ?? false; isDirty |= _audioViewModel?.CheckIfModified(config) ?? false;
isDirty |= _cpuViewModel?.CheckIfModified(config) ?? false; isDirty |= _cpuViewModel?.CheckIfModified(config) ?? false;
isDirty |= _graphicsViewModel?.CheckIfModified(config) ?? false; isDirty |= _graphicsViewModel?.CheckIfModified(config) ?? false;
@ -253,42 +159,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
// isDirty |= _inputViewModel?.CheckIfModified(config) ?? false; // isDirty |= _inputViewModel?.CheckIfModified(config) ?? false;
isDirty |= _loggingViewModel?.CheckIfModified(config) ?? false; isDirty |= _loggingViewModel?.CheckIfModified(config) ?? false;
isDirty |= _networkViewModel?.CheckIfModified(config) ?? false; isDirty |= _networkViewModel?.CheckIfModified(config) ?? false;
isDirty |= _systemViewModel?.CheckIfModified(config) ?? false;
IsModified = isDirty; IsModified = isDirty;
} }
public async Task LoadTimeZones()
{
_timeZoneContentManager = new TimeZoneContentManager();
_timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None);
foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets())
{
int hours = Math.DivRem(offset, 3600, out int seconds);
int minutes = Math.Abs(seconds) / 60;
string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr;
await Dispatcher.UIThread.InvokeAsync(() =>
{
TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2));
_validTzRegions.Add(location);
});
}
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(TimeZone)));
}
public void ValidateAndSetTimeZone(string location)
{
if (_validTzRegions.Contains(location))
{
TimeZone = location;
}
}
public void LoadCurrentConfiguration() public void LoadCurrentConfiguration()
{ {
ConfigurationState config = ConfigurationState.Instance; ConfigurationState config = ConfigurationState.Instance;
@ -303,21 +178,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
GameDirectories.AddRange(config.UI.GameDirs.Value); GameDirectories.AddRange(config.UI.GameDirs.Value);
BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1; BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1;
// System
Region = (int)config.System.Region.Value;
Language = (int)config.System.Language.Value;
TimeZone = config.System.TimeZone;
DateTime currentDateTime = DateTime.Now;
CurrentDate = currentDateTime.Date;
CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset));
EnableVsync = config.Graphics.EnableVsync;
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
ExpandDramSize = config.System.ExpandRam;
IgnoreMissingServices = config.System.IgnoreMissingServices;
} }
public void SaveSettings() public void SaveSettings()
@ -338,22 +198,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
// System
config.System.Region.Value = (Region)Region;
config.System.Language.Value = (Language)Language;
if (_validTzRegions.Contains(TimeZone))
{
config.System.TimeZone.Value = TimeZone;
}
config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
config.Graphics.EnableVsync.Value = EnableVsync;
config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
config.System.ExpandRam.Value = ExpandDramSize;
config.System.IgnoreMissingServices.Value = IgnoreMissingServices;
_audioViewModel?.Save(config); _audioViewModel?.Save(config);
_cpuViewModel?.Save(config); _cpuViewModel?.Save(config);
_graphicsViewModel?.Save(config); _graphicsViewModel?.Save(config);
@ -361,6 +205,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings
_inputViewModel?.Save(config); _inputViewModel?.Save(config);
_loggingViewModel?.Save(config); _loggingViewModel?.Save(config);
_networkViewModel?.Save(config); _networkViewModel?.Save(config);
_systemViewModel?.Save(config);
config.ToFileFormat().SaveConfig(Program.ConfigurationPath); config.ToFileFormat().SaveConfig(Program.ConfigurationPath);

View file

@ -8,12 +8,12 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Settings" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Settings"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsSystemViewModel">
<UserControl.Resources> <UserControl.Resources>
<helpers:TimeZoneConverter x:Key="TimeZone" /> <helpers:TimeZoneConverter x:Key="TimeZone" />
</UserControl.Resources> </UserControl.Resources>
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsSystemViewModel />
</Design.DataContext> </Design.DataContext>
<ScrollViewer <ScrollViewer
Name="SystemPage" Name="SystemPage"

View file

@ -1,16 +1,17 @@
using Avalonia.Controls; using Avalonia.Controls;
using Ryujinx.Ava.UI.ViewModels.Settings; using Ryujinx.Ava.UI.ViewModels.Settings;
using Ryujinx.HLE.FileSystem;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
{ {
public partial class SettingsSystemView : UserControl public partial class SettingsSystemView : UserControl
{ {
private readonly SettingsViewModel _viewModel; public SettingsSystemViewModel ViewModel;
public SettingsSystemView(SettingsViewModel viewModel) public SettingsSystemView(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
{ {
_viewModel = viewModel; DataContext = ViewModel = new SettingsSystemViewModel(virtualFileSystem, contentManager);
InitializeComponent(); InitializeComponent();
} }
@ -22,7 +23,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
e.Handled = true; e.Handled = true;
_viewModel.ValidateAndSetTimeZone(timeZone.Location); ViewModel.ValidateAndSetTimeZone(timeZone.Location);
} }
} }
} }
@ -31,7 +32,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone) if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
{ {
_viewModel.ValidateAndSetTimeZone(timeZone.Location); ViewModel.ValidateAndSetTimeZone(timeZone.Location);
} }
} }
} }

View file

@ -36,20 +36,19 @@ namespace Ryujinx.Ava.UI.Windows
InputPage = new SettingsInputView(); InputPage = new SettingsInputView();
LoggingPage = new SettingsLoggingView(); LoggingPage = new SettingsLoggingView();
NetworkPage = new SettingsNetworkView(); NetworkPage = new SettingsNetworkView();
SystemPage = new SettingsSystemView(virtualFileSystem, contentManager);
ViewModel = new SettingsViewModel( ViewModel = new SettingsViewModel(
virtualFileSystem,
contentManager,
AudioPage.ViewModel, AudioPage.ViewModel,
CpuPage.ViewModel, CpuPage.ViewModel,
GraphicsPage.ViewModel, GraphicsPage.ViewModel,
HotkeysPage.ViewModel, HotkeysPage.ViewModel,
InputPage.ViewModel, InputPage.ViewModel,
LoggingPage.ViewModel, LoggingPage.ViewModel,
NetworkPage.ViewModel); NetworkPage.ViewModel,
SystemPage.ViewModel);
UiPage = new SettingsUiView(ViewModel); UiPage = new SettingsUiView(ViewModel);
SystemPage = new SettingsSystemView(ViewModel);
DataContext = ViewModel; DataContext = ViewModel;