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:
commit
9b6f409a86
17 changed files with 159 additions and 74 deletions
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
@ -27,9 +28,14 @@ namespace Ryujinx.Common.Utilities
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -115,6 +115,9 @@ namespace Ryujinx.Cpu.Jit.HostTracked
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
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 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;
|
||||
|
||||
public AddressSpacePartitionAllocator(
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||
private readonly long[] _current2;
|
||||
private readonly long[] _peak;
|
||||
|
||||
private readonly object _lock = new();
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
private readonly LinkedList<KThread> _waitingThreads;
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
class KCriticalSection
|
||||
{
|
||||
private readonly KernelContext _context;
|
||||
private readonly object _lock = new();
|
||||
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)
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public void Enter()
|
||||
{
|
||||
Monitor.Enter(_lock);
|
||||
Monitor.Enter(Lock);
|
||||
|
||||
_recursionCount++;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
{
|
||||
ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
|
||||
|
||||
Monitor.Exit(_lock);
|
||||
Monitor.Exit(Lock);
|
||||
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
else
|
||||
{
|
||||
Monitor.Exit(_lock);
|
||||
Monitor.Exit(Lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -333,7 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
|
|||
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)
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
|
|||
|
||||
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)
|
||||
seed.AddRange(key.TypeString);
|
||||
|
|
|
@ -33,10 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
|
|||
byte[] dataBin = combinedBin.Take(80).ToArray();
|
||||
byte[] tagBin = combinedBin.Skip(80).Take(80).ToArray();
|
||||
|
||||
AmiiboMasterKey dataKey = new AmiiboMasterKey(dataBin);
|
||||
AmiiboMasterKey tagKey = new AmiiboMasterKey(tagBin);
|
||||
|
||||
return (dataKey, tagKey);
|
||||
return (new AmiiboMasterKey(dataBin), new AmiiboMasterKey(tagBin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
|||
private ulong _value;
|
||||
private readonly EventFdFlags _flags;
|
||||
|
||||
// type is not Lock due to Monitor class usage
|
||||
private readonly object _lock = new();
|
||||
|
||||
public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Gommon;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
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)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
<ResourceDictionary x:Key="Default">
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||
Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</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="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||
|
@ -22,16 +21,19 @@
|
|||
<ResourceDictionary x:Key="Light">
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||
Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<Color x:Key="ControlFillColorSecondary">#3ddcff</Color>
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
|
||||
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#dedede</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#c2c2c2</Color>
|
||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</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 x:Key="Dark">
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||
|
@ -40,13 +42,15 @@
|
|||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</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="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</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.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -2424,25 +2424,25 @@
|
|||
{
|
||||
"ID": "StatusBarSystemVersion",
|
||||
"Translations": {
|
||||
"ar_SA": "إصدار النظام: {0}",
|
||||
"de_DE": "Systemversion: {0}",
|
||||
"el_GR": "Έκδοση Συστήματος: {0}",
|
||||
"en_US": "System Version: {0}",
|
||||
"es_ES": "Versión del sistema: {0}",
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Firmware Version: {0}",
|
||||
"es_ES": "",
|
||||
"fr_FR": "Version du Firmware: {0}",
|
||||
"he_IL": "גרסת מערכת: {0}",
|
||||
"it_IT": "Versione di sistema: {0}",
|
||||
"ja_JP": "システムバージョン: {0}",
|
||||
"ko_KR": "시스템 버전 : {0}",
|
||||
"no_NO": "System versjon: {0}",
|
||||
"pl_PL": "Wersja systemu: {0}",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Versão do firmware: {0}",
|
||||
"ru_RU": "Версия прошивки: {0}",
|
||||
"th_TH": "เวอร์ชั่นของระบบ: {0}",
|
||||
"tr_TR": "Sistem Sürümü: {0}",
|
||||
"uk_UA": "Версія системи: {0}",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "系统固件版本:{0}",
|
||||
"zh_TW": "系統版本: {0}"
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -3765,6 +3765,30 @@
|
|||
"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",
|
||||
"Translations": {
|
||||
|
@ -14541,6 +14565,30 @@
|
|||
"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",
|
||||
"Translations": {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Gommon;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
@ -7,12 +8,7 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
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.Unicode;
|
||||
|
||||
namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
|
@ -147,39 +143,33 @@ namespace Ryujinx.Ava.Common.Locale
|
|||
LocaleChanged?.Invoke();
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
|
||||
private static LocalesJson? _localeData;
|
||||
|
||||
#nullable disable
|
||||
|
||||
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode)
|
||||
{
|
||||
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.
|
||||
return null;
|
||||
}
|
||||
|
||||
LocalesJson json = JsonHelper.Deserialize(fileData, LocalesJsonContext.Default.LocalesJson);
|
||||
|
||||
foreach (LocalesEntry locale in json.Locales)
|
||||
{
|
||||
if (locale.Translations.Count != json.Languages.Count)
|
||||
if (locale.Translations.Count != _localeData.Value.Languages.Count)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.UI, $"Locale key {{{locale.ID}}} is missing languages!");
|
||||
throw new Exception("Missing locale data!");
|
||||
throw new Exception($"Locale key {{{locale.ID}}} is missing languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!");
|
||||
}
|
||||
|
||||
if (Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
|
||||
{
|
||||
if (locale.Translations.TryGetValue(languageCode, out string val) && val != "")
|
||||
{
|
||||
localeStrings[localeKey] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
locale.Translations.TryGetValue("en_US", out val);
|
||||
localeStrings[localeKey] = val;
|
||||
}
|
||||
}
|
||||
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
|
||||
continue;
|
||||
|
||||
localeStrings[localeKey] =
|
||||
locale.Translations.TryGetValue(languageCode, out string val) && val != string.Empty
|
||||
? val
|
||||
: locale.Translations[DefaultLanguageCode];
|
||||
}
|
||||
|
||||
return localeStrings;
|
||||
|
@ -200,5 +190,5 @@ namespace Ryujinx.Ava.Common.Locale
|
|||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(LocalesJson))]
|
||||
internal partial class LocalesJsonContext : JsonSerializerContext { }
|
||||
internal partial class LocalesJsonContext : JsonSerializerContext;
|
||||
}
|
||||
|
|
|
@ -334,7 +334,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
public bool CanScanAmiiboBinaries => AmiiboBinReader.HasKeyRetailBinPath;
|
||||
public bool CanScanAmiiboBinaries => AmiiboBinReader.HasAmiiboKeyFile;
|
||||
|
||||
public bool ShowLoadProgress
|
||||
{
|
||||
|
@ -2015,7 +2015,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
}
|
||||
else
|
||||
{
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "NaN");
|
||||
}
|
||||
|
||||
IsAppletMenuActive = hasApplet;
|
||||
|
|
|
@ -330,6 +330,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
}
|
||||
|
||||
public DateTimeOffset CurrentDate { get; set; }
|
||||
|
||||
public TimeSpan CurrentTime { get; set; }
|
||||
|
||||
internal AvaloniaList<TimeZone> TimeZones { get; set; }
|
||||
|
@ -453,6 +454,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
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()
|
||||
{
|
||||
_timeZoneContentManager = new TimeZoneContentManager();
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
private void ScanBinAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -182,7 +182,20 @@
|
|||
Width="350"
|
||||
ToolTip.Tip="{ext:Locale TimeTooltip}" />
|
||||
</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">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System;
|
||||
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
|
@ -33,5 +35,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
|||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
|
||||
private void MatchSystemTime_OnClick(object sender, RoutedEventArgs e) => ViewModel.MatchSystemTime();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue