0
0
Fork 0
mirror of https://github.com/GreemDev/Ryujinx.git synced 2024-12-22 18:05:46 +00:00

Merge branch 'master' into master

This commit is contained in:
Daenorth 2024-12-22 03:01:37 +01:00 committed by GitHub
commit 9b6f409a86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 159 additions and 74 deletions

View file

@ -1,3 +1,4 @@
using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
@ -27,9 +28,14 @@ namespace Ryujinx.Common.Utilities
ReadCommentHandling = JsonCommentHandling.Skip ReadCommentHandling = JsonCommentHandling.Skip
}; };
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Serialize(value, typeInfo); public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo)
=> JsonSerializer.Serialize(value, typeInfo);
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Deserialize(value, typeInfo); public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo)
=> JsonSerializer.Deserialize(value, typeInfo);
public static T Deserialize<T>(ReadOnlySpan<byte> utf8Value, JsonTypeInfo<T> typeInfo)
=> JsonSerializer.Deserialize<T>(utf8Value, typeInfo);
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo) public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
{ {

View file

@ -115,6 +115,9 @@ namespace Ryujinx.Cpu.Jit.HostTracked
} }
private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree; private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree;
// type is not Lock due to the unique usage of this mechanism,
// an arbitrary object is used as the lock passed in by constructor.
private readonly object _lock; private readonly object _lock;
public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size) public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size)
@ -174,6 +177,9 @@ namespace Ryujinx.Cpu.Jit.HostTracked
private readonly MemoryTracking _tracking; private readonly MemoryTracking _tracking;
private readonly Func<ulong, ulong> _readPtCallback; private readonly Func<ulong, ulong> _readPtCallback;
// type is not Lock due to the unique usage of this mechanism,
// an arbitrary object is used as the lock passed in by constructor.
private readonly object _lock; private readonly object _lock;
public AddressSpacePartitionAllocator( public AddressSpacePartitionAllocator(

View file

@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
private readonly long[] _current2; private readonly long[] _current2;
private readonly long[] _peak; private readonly long[] _peak;
private readonly object _lock = new(); private readonly Lock _lock = new();
private readonly LinkedList<KThread> _waitingThreads; private readonly LinkedList<KThread> _waitingThreads;

View file

@ -5,10 +5,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
class KCriticalSection class KCriticalSection
{ {
private readonly KernelContext _context; private readonly KernelContext _context;
private readonly object _lock = new();
private int _recursionCount; private int _recursionCount;
public object Lock => _lock; // type is not Lock due to Monitor class usage
public object Lock { get; } = new();
public KCriticalSection(KernelContext context) public KCriticalSection(KernelContext context)
{ {
@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public void Enter() public void Enter()
{ {
Monitor.Enter(_lock); Monitor.Enter(Lock);
_recursionCount++; _recursionCount++;
} }
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
ulong scheduledCoresMask = KScheduler.SelectThreads(_context); ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
Monitor.Exit(_lock); Monitor.Exit(Lock);
KThread currentThread = KernelStatic.GetCurrentThread(); KThread currentThread = KernelStatic.GetCurrentThread();
bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable; bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
else else
{ {
Monitor.Exit(_lock); Monitor.Exit(Lock);
} }
} }
} }

View file

@ -333,7 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin"); return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin");
} }
public static bool HasKeyRetailBinPath => File.Exists(GetKeyRetailBinPath()); public static bool HasAmiiboKeyFile => File.Exists(GetKeyRetailBinPath());
public static DateTime DateTimeFromTag(ushort value) public static DateTime DateTimeFromTag(ushort value)

View file

@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
private byte[] DeriveKey(AmiiboMasterKey key, bool deriveAes, out byte[] derivedAesKey, out byte[] derivedAesIv) private byte[] DeriveKey(AmiiboMasterKey key, bool deriveAes, out byte[] derivedAesKey, out byte[] derivedAesIv)
{ {
List<byte> seed = new List<byte>(); List<byte> seed = [];
// Start with the type string (14 bytes) // Start with the type string (14 bytes)
seed.AddRange(key.TypeString); seed.AddRange(key.TypeString);

View file

@ -33,10 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
byte[] dataBin = combinedBin.Take(80).ToArray(); byte[] dataBin = combinedBin.Take(80).ToArray();
byte[] tagBin = combinedBin.Skip(80).Take(80).ToArray(); byte[] tagBin = combinedBin.Skip(80).Take(80).ToArray();
AmiiboMasterKey dataKey = new AmiiboMasterKey(dataBin); return (new AmiiboMasterKey(dataBin), new AmiiboMasterKey(tagBin));
AmiiboMasterKey tagKey = new AmiiboMasterKey(tagBin);
return (dataKey, tagKey);
} }
} }
} }

View file

@ -10,6 +10,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
private ulong _value; private ulong _value;
private readonly EventFdFlags _flags; private readonly EventFdFlags _flags;
// type is not Lock due to Monitor class usage
private readonly object _lock = new(); private readonly object _lock = new();
public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); } public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); }

View file

@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
@ -34,6 +35,8 @@ namespace Ryujinx.UI.Common.Helper
} }
} }
public static void OpenFolder(FilePath path) => OpenFolder(path.Path);
public static void LocateFile(string path) public static void LocateFile(string path)
{ {
if (File.Exists(path)) if (File.Exists(path))

View file

@ -4,11 +4,10 @@
<ResourceDictionary x:Key="Default"> <ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Color="{DynamicResource DataGridSelectionColor}" /> Color="{DynamicResource DataGridSelectionColor}" />
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color> <Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color> <Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
<Color x:Key="ThemeForegroundColor">#FF000000</Color> <Color x:Key="ThemeForegroundColor">#FF000000</Color>
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color> <Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color> <Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
@ -22,16 +21,19 @@
<ResourceDictionary x:Key="Light"> <ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Color="{DynamicResource DataGridSelectionColor}" /> Color="{DynamicResource DataGridSelectionColor}" />
<Color x:Key="ControlFillColorSecondary">#3ddcff</Color>
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color> <Color x:Key="ThemeContentBackgroundColor">#dedede</Color>
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color> <Color x:Key="ThemeControlBorderColor">#c2c2c2</Color>
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
<Color x:Key="ThemeForegroundColor">#FF000000</Color> <Color x:Key="ThemeForegroundColor">#FF000000</Color>
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color> <Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color> <Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color> <Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
<Color x:Key="SecondaryTextColor">#A0000000</Color> <Color x:Key="SecondaryTextColor">#A0000000</Color>
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
<Color x:Key="Switch">#13c3a4</Color>
<Color x:Key="Unbounded">#FFFF4554</Color>
<Color x:Key="Custom">#6483F5</Color>
</ResourceDictionary> </ResourceDictionary>
<ResourceDictionary x:Key="Dark"> <ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
@ -40,13 +42,15 @@
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color> <Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
<Color x:Key="ThemeControlBorderColor">#FF505050</Color> <Color x:Key="ThemeControlBorderColor">#FF505050</Color>
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color> <Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color> <Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color> <Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color> <Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color> <Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
<Color x:Key="Switch">#FF2EEAC9</Color>
<Color x:Key="Unbounded">#FFFF4554</Color>
<Color x:Key="Custom">#6483F5</Color>
</ResourceDictionary> </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries> </ResourceDictionary.ThemeDictionaries>
</ResourceDictionary> </ResourceDictionary>

View file

@ -2424,25 +2424,25 @@
{ {
"ID": "StatusBarSystemVersion", "ID": "StatusBarSystemVersion",
"Translations": { "Translations": {
"ar_SA": "إصدار النظام: {0}", "ar_SA": "",
"de_DE": "Systemversion: {0}", "de_DE": "",
"el_GR": "Έκδοση Συστήματος: {0}", "el_GR": "",
"en_US": "System Version: {0}", "en_US": "Firmware Version: {0}",
"es_ES": "Versión del sistema: {0}", "es_ES": "",
"fr_FR": "Version du Firmware: {0}", "fr_FR": "Version du Firmware: {0}",
"he_IL": "גרסת מערכת: {0}", "he_IL": "",
"it_IT": "Versione di sistema: {0}", "it_IT": "",
"ja_JP": "システムバージョン: {0}", "ja_JP": "",
"ko_KR": "시스템 버전 : {0}", "ko_KR": "",
"no_NO": "System versjon: {0}", "no_NO": "",
"pl_PL": "Wersja systemu: {0}", "pl_PL": "",
"pt_BR": "Versão do firmware: {0}", "pt_BR": "Versão do firmware: {0}",
"ru_RU": "Версия прошивки: {0}", "ru_RU": "Версия прошивки: {0}",
"th_TH": "เวอร์ชั่นของระบบ: {0}", "th_TH": "",
"tr_TR": "Sistem Sürümü: {0}", "tr_TR": "",
"uk_UA": "Версія системи: {0}", "uk_UA": "",
"zh_CN": "系统固件版本:{0}", "zh_CN": "系统固件版本:{0}",
"zh_TW": "系統版本: {0}" "zh_TW": ""
} }
}, },
{ {
@ -3765,6 +3765,30 @@
"zh_TW": "系統時鐘:" "zh_TW": "系統時鐘:"
} }
}, },
{
"ID": "SettingsTabSystemSystemTimeMatch",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Match PC Time",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "SettingsTabSystemEnablePptc", "ID": "SettingsTabSystemEnablePptc",
"Translations": { "Translations": {
@ -14541,6 +14565,30 @@
"zh_TW": "變更系統時鐘" "zh_TW": "變更系統時鐘"
} }
}, },
{
"ID": "MatchTimeTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Change System Time to match your PC's date & time.",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "VSyncToggleTooltip", "ID": "VSyncToggleTooltip",
"Translations": { "Translations": {
@ -21550,4 +21598,4 @@
} }
} }
] ]
} }

View file

@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@ -7,12 +8,7 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.Unicode;
namespace Ryujinx.Ava.Common.Locale namespace Ryujinx.Ava.Common.Locale
{ {
@ -147,39 +143,33 @@ namespace Ryujinx.Ava.Common.Locale
LocaleChanged?.Invoke(); LocaleChanged?.Invoke();
} }
#nullable enable
private static LocalesJson? _localeData;
#nullable disable
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode) private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode)
{ {
var localeStrings = new Dictionary<LocaleKeys, string>(); var localeStrings = new Dictionary<LocaleKeys, string>();
string fileData = EmbeddedResources.ReadAllText($"Ryujinx/Assets/locales.json");
if (fileData == null) _localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json")
.Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson));
foreach (LocalesEntry locale in _localeData.Value.Locales)
{ {
// We were unable to find file for that language code. if (locale.Translations.Count != _localeData.Value.Languages.Count)
return null;
}
LocalesJson json = JsonHelper.Deserialize(fileData, LocalesJsonContext.Default.LocalesJson);
foreach (LocalesEntry locale in json.Locales)
{
if (locale.Translations.Count != json.Languages.Count)
{ {
Logger.Error?.Print(LogClass.UI, $"Locale key {{{locale.ID}}} is missing languages!"); throw new Exception($"Locale key {{{locale.ID}}} is missing languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!");
throw new Exception("Missing locale data!");
} }
if (Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey)) if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
{ continue;
if (locale.Translations.TryGetValue(languageCode, out string val) && val != "")
{ localeStrings[localeKey] =
localeStrings[localeKey] = val; locale.Translations.TryGetValue(languageCode, out string val) && val != string.Empty
} ? val
else : locale.Translations[DefaultLanguageCode];
{
locale.Translations.TryGetValue("en_US", out val);
localeStrings[localeKey] = val;
}
}
} }
return localeStrings; return localeStrings;
@ -200,5 +190,5 @@ namespace Ryujinx.Ava.Common.Locale
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(LocalesJson))] [JsonSerializable(typeof(LocalesJson))]
internal partial class LocalesJsonContext : JsonSerializerContext { } internal partial class LocalesJsonContext : JsonSerializerContext;
} }

View file

@ -334,7 +334,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public bool CanScanAmiiboBinaries => AmiiboBinReader.HasKeyRetailBinPath; public bool CanScanAmiiboBinaries => AmiiboBinReader.HasAmiiboKeyFile;
public bool ShowLoadProgress public bool ShowLoadProgress
{ {
@ -2015,7 +2015,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
else else
{ {
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0"); LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "NaN");
} }
IsAppletMenuActive = hasApplet; IsAppletMenuActive = hasApplet;

View file

@ -330,6 +330,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
public DateTimeOffset CurrentDate { get; set; } public DateTimeOffset CurrentDate { get; set; }
public TimeSpan CurrentTime { get; set; } public TimeSpan CurrentTime { get; set; }
internal AvaloniaList<TimeZone> TimeZones { get; set; } internal AvaloniaList<TimeZone> TimeZones { get; set; }
@ -453,6 +454,18 @@ namespace Ryujinx.Ava.UI.ViewModels
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex))); Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex)));
} }
public void MatchSystemTime()
{
var dto = DateTimeOffset.Now;
CurrentDate = new DateTimeOffset(dto.Year, dto.Month, dto.Day, 0, 0, 0, dto.Offset);
CurrentTime = dto.TimeOfDay;
OnPropertyChanged(nameof(CurrentDate));
OnPropertyChanged(nameof(CurrentTime));
}
public async Task LoadTimeZones() public async Task LoadTimeZones()
{ {
_timeZoneContentManager = new TimeZoneContentManager(); _timeZoneContentManager = new TimeZoneContentManager();

View file

@ -178,7 +178,7 @@ namespace Ryujinx.Ava.UI.Views.Main
private void ScanBinAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e) private void ScanBinAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
{ {
if (sender is MenuItem) if (sender is MenuItem)
ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasKeyRetailBinPath; ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile;
} }
private async void InstallFileTypes_Click(object sender, RoutedEventArgs e) private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)

View file

@ -182,7 +182,20 @@
Width="350" Width="350"
ToolTip.Tip="{ext:Locale TimeTooltip}" /> ToolTip.Tip="{ext:Locale TimeTooltip}" />
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" <StackPanel
Margin="350,0,0,10"
Orientation="Horizontal">
<Button
VerticalAlignment="Center"
Click="MatchSystemTime_OnClick"
Background="{DynamicResource SystemAccentColor}"
Width="150"
ToolTip.Tip="{ext:Locale MatchTimeTooltip}">
<TextBlock Text="{ext:Locale SettingsTabSystemSystemTimeMatch}" />
</Button>
</StackPanel>
<Separator />
<StackPanel Margin="0,10,0,10"
Orientation="Horizontal"> Orientation="Horizontal">
<TextBlock <TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"

View file

@ -1,5 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using System;
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
@ -33,5 +35,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
ViewModel.ValidateAndSetTimeZone(timeZone.Location); ViewModel.ValidateAndSetTimeZone(timeZone.Location);
} }
} }
private void MatchSystemTime_OnClick(object sender, RoutedEventArgs e) => ViewModel.MatchSystemTime();
} }
} }