From 71fcbc367c2b76e4e44a5c55cfb1c77ccc3ba88e Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Fri, 11 Aug 2023 16:12:11 +0800 Subject: [PATCH] refactor string cultureinfo --- src/Snap.Hutao/.editorconfig | 153 +++++++++++++++++- .../UniversalAnalyzer.cs | 3 + .../Snap.Hutao.Test/JsonSerializeTest.cs | 4 +- .../Snap.Hutao/CodeMetricsConfig.txt | 1 + .../Control/Image/CompositionImage.cs | 3 +- .../Control/Markup/ResourceStringExtension.cs | 3 +- .../Core/Annotation/HighQualityAttribute.cs | 2 +- .../DatabaseCorruptedException.cs | 2 +- .../Core/ExceptionService/ExceptionFormat.cs | 3 +- .../UserdataCorruptedException.cs | 2 +- .../Snap.Hutao/Core/IO/Hashing/MD5.cs | 9 +- .../Snap.Hutao/Core/IO/Hashing/XXH64.cs | 2 +- .../Snap.Hutao/Core/IO/Ini/IniSerializer.cs | 17 +- .../Snap.Hutao/Core/IO/PickerExtension.cs | 2 +- .../Snap.Hutao/Core/IO/ValueFile.cs | 1 + .../Core/Json/Annotation/JsonEnumAttribute.cs | 2 +- .../Json/Converter/DateTimeOffsetConverter.cs | 8 +- .../SeparatorCommaInt32EnumerableConverter.cs | 3 +- .../Snap.Hutao/Core/LifeCycle/Activation.cs | 14 +- .../Snap.Hutao/Core/Setting/LocalSetting.cs | 7 +- .../Threading/DispatcherQueueExtension.cs | 14 +- .../Snap.Hutao/Core/TypeNameHelper.cs | 2 +- .../Core/Windowing/ExtendedWindow.cs | 9 +- .../Snap.Hutao/Extension/StringExtension.cs | 13 ++ .../Configuration/JsonTextValueConverter.cs | 4 +- .../Entity/Configuration/UserConfiguration.cs | 1 + .../Snap.Hutao/Model/Entity/GachaItem.cs | 3 +- .../Model/Entity/SpiralAbyssEntry.cs | 2 +- .../Model/Metadata/Avatar/FetterInfo.cs | 2 +- .../Converter/AvatarNameCardPicConverter.cs | 2 +- .../DescriptionsParametersDescriptor.cs | 5 +- .../Metadata/Converter/FightPropertyFormat.cs | 2 +- .../Model/Metadata/ParameterFormat.cs | 10 +- .../Resource/Localization/SH.Designer.cs | 9 ++ .../Snap.Hutao/Resource/Localization/SH.resx | 9 +- src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 2 + .../Snap.Hutao/View/Page/SettingPage.xaml | 6 +- .../ExperimentalFeaturesViewModel.cs | 58 ------- .../ViewModel/HutaoPassportViewModel.cs | 57 +++---- .../Snap.Hutao/ViewModel/SettingViewModel.cs | 50 ++++-- 40 files changed, 328 insertions(+), 173 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/CodeMetricsConfig.txt delete mode 100644 src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs diff --git a/src/Snap.Hutao/.editorconfig b/src/Snap.Hutao/.editorconfig index bea15828..fc537b99 100644 --- a/src/Snap.Hutao/.editorconfig +++ b/src/Snap.Hutao/.editorconfig @@ -57,6 +57,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_namespace_match_folder = true:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_member_access = true:silent +dotnet_diagnostic.CA1000.severity = suggestion [*.cs] #### 命名样式 #### @@ -162,7 +163,7 @@ dotnet_diagnostic.CA1309.severity = suggestion dotnet_diagnostic.CA1805.severity = suggestion # VSTHRD111: Use ConfigureAwait(bool) -dotnet_diagnostic.VSTHRD111.severity = suggestion +dotnet_diagnostic.VSTHRD111.severity = silent csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_readonly_struct = true:suggestion csharp_style_prefer_utf8_string_literals = true:suggestion @@ -172,6 +173,156 @@ dotnet_diagnostic.SA1600.severity = none dotnet_diagnostic.SA1601.severity = silent dotnet_diagnostic.SA1602.severity = silent +# CA1008: 枚举应具有零值 +dotnet_diagnostic.CA1008.severity = suggestion + +# CA1010: 还应实现泛型接口 +dotnet_diagnostic.CA1010.severity = suggestion + +# CA1012: 抽象类型不应具有公共构造函数 +dotnet_diagnostic.CA1012.severity = suggestion + +# CA1024: 在适用处使用属性 +dotnet_diagnostic.CA1024.severity = suggestion + +# CA1034: 嵌套类型应不可见 +dotnet_diagnostic.CA1034.severity = suggestion + +# CA1036: 重写可比较类型中的方法 +dotnet_diagnostic.CA1036.severity = suggestion + +# CA1040: 避免使用空接口 +dotnet_diagnostic.CA1040.severity = suggestion + +# CA1044: 属性不应是只写的 +dotnet_diagnostic.CA1044.severity = suggestion + +# CA1043: 将整型或字符串参数用于索引器 +dotnet_diagnostic.CA1043.severity = suggestion + +# CA1046: 不要对引用类型重载相等运算符 +dotnet_diagnostic.CA1046.severity = suggestion + +# CA1051: 不要声明可见实例字段 +dotnet_diagnostic.CA1051.severity = suggestion + +# CA1052: 静态容器类型应为 Static 或 NotInheritable +dotnet_diagnostic.CA1052.severity = suggestion + +# CA1058: 类型不应扩展某些基类型 +dotnet_diagnostic.CA1058.severity = suggestion + +# CA1063: 正确实现 IDisposable +dotnet_diagnostic.CA1063.severity = suggestion + +# CA1065: 不要在意外的位置引发异常 +dotnet_diagnostic.CA1065.severity = suggestion + +# CA1066: 重写 Object.Equals 时实现 IEquatable +dotnet_diagnostic.CA1066.severity = suggestion + +# CA1304: 指定 CultureInfo +dotnet_diagnostic.CA1304.severity = suggestion + +# CA1305: 指定 IFormatProvider +dotnet_diagnostic.CA1305.severity = suggestion + +# CA1307: 为了清晰起见,请指定 StringComparison +dotnet_diagnostic.CA1307.severity = suggestion + +# CA1310: 为了确保正确,请指定 StringComparison +dotnet_diagnostic.CA1310.severity = suggestion + +# CA1308: 将字符串规范化为大写 +dotnet_diagnostic.CA1308.severity = suggestion + +# CA1501: 避免过度继承 +dotnet_diagnostic.CA1501.severity = suggestion + +# CA1502: 避免过度复杂性 +dotnet_diagnostic.CA1502.severity = suggestion + +# CA1505: 避免使用无法维护的代码 +dotnet_diagnostic.CA1505.severity = suggestion + +# CA1506: 避免过度的类耦合 +dotnet_diagnostic.CA1506.severity = suggestion + +# CA1508: 避免死条件代码 +dotnet_diagnostic.CA1508.severity = suggestion + +# CA1810: 以内联方式初始化引用类型的静态字段 +dotnet_diagnostic.CA1810.severity = suggestion + +# CA1813: 避免使用非密封特性 +dotnet_diagnostic.CA1813.severity = suggestion + +# CA1814: 与多维数组相比,首选使用交错数组 +dotnet_diagnostic.CA1814.severity = suggestion + +# CA1819: 属性不应返回数组 +dotnet_diagnostic.CA1819.severity = suggestion + +# CA1820: 使用字符串长度测试是否有空字符串 +dotnet_diagnostic.CA1820.severity = suggestion + +# CA1823: 避免未使用的私有字段 +dotnet_diagnostic.CA1823.severity = suggestion + +# CA1849: 当在异步方法中时,调用异步方法 +dotnet_diagnostic.CA1849.severity = suggestion + +# CA1852: 密封内部类型 +dotnet_diagnostic.CA1852.severity = suggestion + +# CA2000: 丢失范围之前释放对象 +dotnet_diagnostic.CA2000.severity = suggestion + +# CA2002: 不要锁定具有弱标识的对象 +dotnet_diagnostic.CA2002.severity = suggestion + +# CA2007: 考虑对等待的任务调用 ConfigureAwait +dotnet_diagnostic.CA2007.severity = suggestion + +# CA2008: 不要在未传递 TaskScheduler 的情况下创建任务 +dotnet_diagnostic.CA2008.severity = suggestion + +# CA2100: 检查 SQL 查询是否存在安全漏洞 +dotnet_diagnostic.CA2100.severity = suggestion + +# CA2109: 检查可见的事件处理程序 +dotnet_diagnostic.CA2109.severity = suggestion + +# CA2119: 密封满足私有接口的方法 +dotnet_diagnostic.CA2119.severity = suggestion + +# CA2153: 不要捕获损坏状态异常 +dotnet_diagnostic.CA2153.severity = suggestion + +# CA2201: 不要引发保留的异常类型 +dotnet_diagnostic.CA2201.severity = suggestion + +# CA2207: 以内联方式初始化值类型的静态字段 +dotnet_diagnostic.CA2207.severity = suggestion + +# CA2213: 应释放可释放的字段 +dotnet_diagnostic.CA2213.severity = suggestion + +# CA2214: 不要在构造函数中调用可重写的方法 +dotnet_diagnostic.CA2214.severity = suggestion + +# CA2215: Dispose 方法应调用基类释放 +dotnet_diagnostic.CA2215.severity = suggestion + +# CA2216: 可释放类型应声明终结器 +dotnet_diagnostic.CA2216.severity = suggestion + +# CA2227: 集合属性应为只读 +dotnet_diagnostic.CA2227.severity = suggestion + +# CA2251: 使用 “string.Equals” +dotnet_diagnostic.CA2251.severity = suggestion + [*.vb] #### 命名样式 #### diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/UniversalAnalyzer.cs b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/UniversalAnalyzer.cs index 31b679d4..cbffff49 100644 --- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/UniversalAnalyzer.cs +++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/UniversalAnalyzer.cs @@ -78,6 +78,9 @@ internal sealed class UniversalAnalyzer : DiagnosticAnalyzer context.RegisterSyntaxNodeAction(HandleEqualsAndNotEqualsExpressionShouldUsePatternMatching, expressions); context.RegisterSyntaxNodeAction(HandleIsPatternShouldUseRecursivePattern, SyntaxKind.IsPatternExpression); context.RegisterSyntaxNodeAction(HandleArgumentNullExceptionThrowIfNull, SyntaxKind.SuppressNullableWarningExpression); + + // TODO add analyzer for unnecessary IServiceProvider registration + // TODO add analyzer for Singlton service use Scoped or Transient services } private static void HandleTypeShouldBeInternal(SyntaxNodeAnalysisContext context) diff --git a/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs b/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs index bfc05c2c..eb6473bb 100644 --- a/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs +++ b/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs @@ -53,13 +53,13 @@ public class JsonSerializeTest Assert.AreEqual(sample[111], "12"); } - private class Sample + private sealed class Sample { public int A { get => B; set => B = value; } public int B { get; set; } } - private class StringNumberSample + private sealed class StringNumberSample { [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public int A { get; set; } diff --git a/src/Snap.Hutao/Snap.Hutao/CodeMetricsConfig.txt b/src/Snap.Hutao/Snap.Hutao/CodeMetricsConfig.txt new file mode 100644 index 00000000..7e7498af --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/CodeMetricsConfig.txt @@ -0,0 +1 @@ +CA1501: 6 \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs index dfe468a0..7ffe983a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs @@ -10,6 +10,7 @@ using Snap.Hutao.Control.Animation; using Snap.Hutao.Control.Extension; using Snap.Hutao.Core.Caching; using Snap.Hutao.Service.Notification; +using System.Globalization; using System.IO; using System.Net.Http; using System.Runtime.InteropServices; @@ -110,7 +111,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co if (exception is HttpRequestException httpRequestException) { - infoBarService.Error(httpRequestException, string.Format(SH.ControlImageCompositionImageHttpRequest, uri)); + infoBarService.Error(httpRequestException, SH.ControlImageCompositionImageHttpRequest.Format(uri)); } else { diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs index 2e71149d..92de4ac5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Markup; +using System.Globalization; namespace Snap.Hutao.Control.Markup; @@ -20,6 +21,6 @@ internal sealed class ResourceStringExtension : MarkupExtension /// protected override object ProvideValue() { - return SH.ResourceManager.GetString(Name ?? string.Empty) ?? Name ?? string.Empty; + return SH.ResourceManager.GetString(Name ?? string.Empty, CultureInfo.CurrentCulture) ?? Name ?? string.Empty; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs index b98f4f2b..0757aaf0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs @@ -7,6 +7,6 @@ namespace Snap.Hutao.Core.Annotation; /// 高质量代码 /// [AttributeUsage(AttributeTargets.All, Inherited = false)] -internal class HighQualityAttribute : Attribute +internal sealed class HighQualityAttribute : Attribute { } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/DatabaseCorruptedException.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/DatabaseCorruptedException.cs index bfc11386..1c31ff82 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/DatabaseCorruptedException.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/DatabaseCorruptedException.cs @@ -15,7 +15,7 @@ internal sealed class DatabaseCorruptedException : Exception /// 消息 /// 内部错误 public DatabaseCorruptedException(string message, Exception? innerException) - : base(string.Format(SH.CoreExceptionServiceDatabaseCorruptedMessage, $"{message}\n{innerException?.Message}"), innerException) + : base(SH.CoreExceptionServiceDatabaseCorruptedMessage.Format($"{message}\n{innerException?.Message}"), innerException) { } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionFormat.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionFormat.cs index de50e2e8..489bef51 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionFormat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionFormat.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections; +using System.Globalization; using System.Text; namespace Snap.Hutao.Core.ExceptionService; @@ -25,7 +26,7 @@ internal sealed class ExceptionFormat foreach (DictionaryEntry entry in exception.Data) { - builder.AppendLine($"{entry.Key}:[{TypeNameHelper.GetTypeDisplayName(entry.Value)}]:entry.Value"); + builder.AppendLine(CultureInfo.CurrentCulture, $"[{TypeNameHelper.GetTypeDisplayName(entry.Value)}]:{entry.Key}:{entry.Value}"); } builder.AppendLine(SectionSeparator); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs index dae43281..ee6880d8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs @@ -15,7 +15,7 @@ internal sealed class UserdataCorruptedException : Exception /// 消息 /// 内部错误 public UserdataCorruptedException(string message, Exception? innerException) - : base(string.Format(SH.CoreExceptionServiceUserdataCorruptedMessage, $"{message}\n{innerException?.Message}"), innerException) + : base(SH.CoreExceptionServiceUserdataCorruptedMessage.Format($"{message}\n{innerException?.Message}"), innerException) { } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs index 52c50631..47f4e25a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs @@ -19,7 +19,7 @@ internal static class MD5 /// 文件 Md5 摘要 public static async ValueTask HashFileAsync(string filePath, CancellationToken token = default) { - await using (FileStream stream = File.OpenRead(filePath)) + using (FileStream stream = File.OpenRead(filePath)) { return await HashAsync(stream, token).ConfigureAwait(false); } @@ -33,10 +33,7 @@ internal static class MD5 /// 流 Md5 摘要 public static async ValueTask HashAsync(Stream stream, CancellationToken token = default) { - using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) - { - byte[] bytes = await md5.ComputeHashAsync(stream, token).ConfigureAwait(false); - return System.Convert.ToHexString(bytes); - } + byte[] bytes = await System.Security.Cryptography.MD5.HashDataAsync(stream, token).ConfigureAwait(false); + return System.Convert.ToHexString(bytes); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs index e68d285a..6999bb5e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs @@ -33,7 +33,7 @@ internal static class XXH64 /// 摘要 public static async ValueTask HashFileAsync(string path, CancellationToken token = default) { - await using (FileStream stream = File.OpenRead(path)) + using (FileStream stream = File.OpenRead(path)) { return await HashAsync(stream, token).ConfigureAwait(false); } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs index 9a9b659c..15293298 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs @@ -22,25 +22,26 @@ internal static class IniSerializer { while (reader.ReadLine() is { } line) { - if (line.Length <= 0) + if (string.IsNullOrEmpty(line)) { continue; } - if (line[0] == '[') + ReadOnlySpan lineSpan = line; + + if (lineSpan[0] is '[') { - yield return new IniSection(line[1..^1]); + yield return new IniSection(lineSpan[1..^1].ToString()); } - if (line[0] == ';') + if (lineSpan[0] is ';') { - yield return new IniComment(line[1..]); + yield return new IniComment(lineSpan[1..].ToString()); } - if (line.IndexOf('=') > 0) + if (lineSpan.TrySplitIntoTwo('=', out ReadOnlySpan left, out ReadOnlySpan right)) { - string[] parameters = line.Split('=', 2, StringSplitOptions.TrimEntries); - yield return new IniParameter(parameters[0], parameters[1]); + yield return new IniParameter(left.Trim().ToString(), right.Trim().ToString()); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs index 11169cb9..76cf669e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs @@ -98,7 +98,7 @@ internal static class PickerExtension .GetRequiredService() .Warning( SH.CoreIOPickerExtensionPickerExceptionInfoBarTitle, - string.Format(SH.CoreIOPickerExtensionPickerExceptionInfoBarMessage, exception.Message)); + SH.CoreIOPickerExtensionPickerExceptionInfoBarMessage.Format(exception.Message)); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFile.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFile.cs index 8e48cc36..cdd0b610 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFile.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFile.cs @@ -80,6 +80,7 @@ internal readonly struct ValueFile } /// + [SuppressMessage("", "CA1307")] public override int GetHashCode() { return value.GetHashCode(); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Annotation/JsonEnumAttribute.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Annotation/JsonEnumAttribute.cs index 5b5d71c8..5c0515a1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Annotation/JsonEnumAttribute.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Annotation/JsonEnumAttribute.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Core.Json.Annotation; /// Json 枚举类型 /// [AttributeUsage(AttributeTargets.Property)] -internal class JsonEnumAttribute : Attribute +internal sealed class JsonEnumAttribute : Attribute { private static readonly Type UnsafeEnumConverterType = typeof(UnsafeEnumConverter<>); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs index 9f118f89..be8eaef3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using System.Globalization; + namespace Snap.Hutao.Core.Json.Converter; /// @@ -9,12 +11,14 @@ namespace Snap.Hutao.Core.Json.Converter; [HighQuality] internal class DateTimeOffsetConverter : JsonConverter { + private const string Format = "yyyy-MM-dd HH:mm:ss"; + /// public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.GetString() is { } dataTimeString) { - return DateTimeOffset.Parse(dataTimeString); + return DateTimeOffset.ParseExact(dataTimeString, Format, CultureInfo.CurrentCulture); } return default; @@ -23,6 +27,6 @@ internal class DateTimeOffsetConverter : JsonConverter /// public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) { - writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + writer.WriteStringValue(value.ToString(Format, CultureInfo.CurrentCulture)); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs index 183e37c3..bffefbb1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.Extensions.Primitives; +using System.Globalization; namespace Snap.Hutao.Core.Json.Converter; @@ -35,7 +36,7 @@ internal sealed class SeparatorCommaInt32EnumerableConverter : JsonConverter public const string ImportUIAFFromClipboard = nameof(ImportUIAFFromClipboard); - private const string CategoryAchievement = "achievement"; - private const string CategoryDailyNote = "dailynote"; - private const string UrlActionImport = "/import"; - private const string UrlActionRefresh = "/refresh"; + private const string CategoryAchievement = "ACHIEVEMENT"; + private const string CategoryDailyNote = "DAILYNOTE"; + private const string UrlActionImport = "/IMPORT"; + private const string UrlActionRefresh = "/REFRESH"; private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; @@ -187,9 +187,9 @@ internal sealed class Activation : IActivation { UriBuilder builder = new(uri); - string category = builder.Host.ToLowerInvariant(); - string action = builder.Path.ToLowerInvariant(); - string parameter = builder.Query.ToLowerInvariant(); + string category = builder.Host.ToUpperInvariant(); + string action = builder.Path.ToUpperInvariant(); + string parameter = builder.Query.ToUpperInvariant(); switch (category) { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs index 0892aa5c..23a50292 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs @@ -11,12 +11,7 @@ namespace Snap.Hutao.Core.Setting; [HighQuality] internal static class LocalSetting { - private static readonly ApplicationDataContainer Container; - - static LocalSetting() - { - Container = ApplicationData.Current.LocalSettings; - } + private static readonly ApplicationDataContainer Container = ApplicationData.Current.LocalSettings; /// public static byte Get(string key, byte defaultValue) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs index 9bfa00f4..a353ad31 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs @@ -18,13 +18,15 @@ internal static class DispatcherQueueExtension /// 执行的回调 public static void Invoke(this DispatcherQueue dispatcherQueue, Action action) { - ManualResetEventSlim blockEvent = new(); - dispatcherQueue.TryEnqueue(() => + using (ManualResetEventSlim blockEvent = new()) { - action(); - blockEvent.Set(); - }); + dispatcherQueue.TryEnqueue(() => + { + action(); + blockEvent.Set(); + }); - blockEvent.Wait(); + blockEvent.Wait(); + } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs index 50813f17..66b635b9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/TypeNameHelper.cs @@ -161,7 +161,7 @@ internal static class TypeNameHelper } } - int genericPartIndex = type.Name.IndexOf('`'); + int genericPartIndex = type.Name.AsSpan().IndexOf('`'); if (genericPartIndex <= 0) { builder.Append(type.Name); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs index 0ec57711..8647fee6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs @@ -29,7 +29,7 @@ internal sealed class ExtendedWindow : IRecipient? subclass; + private readonly WindowSubclass subclass; private ExtendedWindow(TWindow window, IServiceProvider serviceProvider) { @@ -63,7 +63,7 @@ internal sealed class ExtendedWindow : IRecipient(); WindowOptions options = window.WindowOptions; - window.AppWindow.Title = string.Format(SH.AppNameAndVersion, hutaoOptions.Version); + window.AppWindow.Title = SH.AppNameAndVersion.Format(hutaoOptions.Version); window.AppWindow.SetIcon(Path.Combine(hutaoOptions.InstalledLocation, "Assets/Logo.ico")); ExtendsContentIntoTitleBar(); @@ -79,7 +79,7 @@ internal sealed class ExtendedWindow : IRecipient().Register(this); @@ -91,7 +91,8 @@ internal sealed class ExtendedWindow : IRecipient : ValueConverter { - /// - /// Initializes a new instance of the class. - /// + [SuppressMessage("", "SH007")] public JsonTextValueConverter() : base( obj => JsonSerializer.Serialize(obj, JsonOptions.Default), diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs index e62357c9..d25053da 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs @@ -14,6 +14,7 @@ namespace Snap.Hutao.Model.Entity.Configuration; internal sealed class UserConfiguration : IEntityTypeConfiguration { /// + [SuppressMessage("", "SH007")] public void Configure(EntityTypeBuilder builder) { builder.Property(e => e.CookieToken) diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs index 18cca2f4..0da36891 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs @@ -7,6 +7,7 @@ using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Globalization; namespace Snap.Hutao.Model.Entity; @@ -119,7 +120,7 @@ internal sealed partial class GachaItem ArchiveId = archiveId, GachaType = item.GachaType, QueryType = item.UIGFGachaType, - ItemId = uint.Parse(item.ItemId), + ItemId = uint.Parse(item.ItemId, CultureInfo.CurrentCulture), Time = item.Time, Id = item.Id, }; diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SpiralAbyssEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SpiralAbyssEntry.cs index 598123b1..ad52f3b8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SpiralAbyssEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SpiralAbyssEntry.cs @@ -32,7 +32,7 @@ internal sealed class SpiralAbyssEntry : ObservableObject, /// 视图 中使用的计划 Id 字符串 /// [NotMapped] - public string Schedule { get => string.Format(SH.ModelEntitySpiralAbyssScheduleFormat, ScheduleId); } + public string Schedule { get => SH.ModelEntitySpiralAbyssScheduleFormat.Format(ScheduleId); } /// /// Uid diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs index 6464e494..bea90e4d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs @@ -47,7 +47,7 @@ internal sealed class FetterInfo /// public string BirthFormatted { - get => string.Format(SH.ModelMetadataFetterInfoBirthdayFormat, BirthMonth, BirthDay); + get => SH.ModelMetadataFetterInfoBirthdayFormat.Format(BirthMonth, BirthDay); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarNameCardPicConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarNameCardPicConverter.cs index d81abc38..537ab313 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarNameCardPicConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarNameCardPicConverter.cs @@ -20,7 +20,7 @@ internal sealed class AvatarNameCardPicConverter : ValueConverter $"{MathF.Round(value, MidpointRounding.AwayFromZero)}", FormatMethod.Percent => $"{value:P1}", - _ => value.ToString(), + _ => $"{value}", }; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterFormat.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterFormat.cs index d80eea9a..ee136936 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterFormat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterFormat.cs @@ -17,7 +17,7 @@ internal sealed class ParameterFormat : IFormatProvider, ICustomFormatter /// 字符串 /// 参数 /// 格式化的字符串 - public static string Format(string str, object param) + public static string Format(string str, object param, IFormatProvider? formatProvider = default) { return string.Format(LazyFormat.Value, str, param); } @@ -29,16 +29,16 @@ internal sealed class ParameterFormat : IFormatProvider, ICustomFormatter switch (fmtSpan.Length) { case 3: // FnP - return string.Format($"{{0:P{fmtSpan[1]}}}", arg); + return string.Format(formatProvider, $"{{0:P{fmtSpan[1]}}}", arg); case 2: // Fn - return string.Format($"{{0:{fmtSpan}}}", arg); + return string.Format(formatProvider, $"{{0:{fmtSpan}}}", arg); case 1: // P I switch (fmtSpan[0]) { case 'P': - return string.Format($"{{0:P0}}", arg); + return string.Format(formatProvider, $"{{0:P0}}", arg); case 'I': - return arg is null ? "0" : ((IConvertible)arg).ToInt32(default).ToString(); + return arg is null ? "0" : ((IConvertible)arg).ToInt32(default).ToString(formatProvider); } break; diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index 68d37009..42b8fb9c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -2733,6 +2733,15 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 请输入正确的邮箱 的本地化字符串。 + /// + internal static string ViewModelHutaoPassportEmailNotValidHint { + get { + return ResourceManager.GetString("ViewModelHutaoPassportEmailNotValidHint", resourceCulture); + } + } + /// /// 查找类似 剪贴板中的文本格式不正确 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 9461be20..aba5c5d6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -824,12 +824,12 @@ 探索派遣完成提醒 - - 原粹树脂提醒阈值 - 洞天宝钱提醒阈值 + + 原粹树脂提醒阈值 + 在主页显示卡片 @@ -1064,6 +1064,9 @@ 正在上传到胡桃云服务 + + 请输入正确的邮箱 + 剪贴板中的文本格式不正确 diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 2543fed3..4f6ee785 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -71,6 +71,7 @@ + @@ -161,6 +162,7 @@ + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml index 79d01458..a7b9acd4 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml @@ -150,7 +150,7 @@ -/// 实验性功能视图模型 -/// -[HighQuality] -[ConstructorGenerated] -[Injection(InjectAs.Scoped)] -internal sealed partial class ExperimentalFeaturesViewModel : ObservableObject -{ - private readonly IServiceProvider serviceProvider; - - [Command("OpenCacheFolderCommand")] - private Task OpenCacheFolderAsync() - { - RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService(); - return Launcher.LaunchFolderPathAsync(hutaoOptions.LocalCache).AsTask(); - } - - [Command("OpenDataFolderCommand")] - private Task OpenDataFolderAsync() - { - RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService(); - return Launcher.LaunchFolderPathAsync(hutaoOptions.DataFolder).AsTask(); - } - - [Command("DeleteUsersCommand")] - private async Task DangerousDeleteUsersAsync() - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - ContentDialogResult result = await scope.ServiceProvider - .GetRequiredService() - .CreateForConfirmCancelAsync(SH.ViewDialogSettingDeleteUserDataTitle, SH.ViewDialogSettingDeleteUserDataContent) - .ConfigureAwait(false); - - if (result == ContentDialogResult.Primary) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.Users.ExecuteDeleteAsync().ConfigureAwait(false); - - AppInstance.Restart(string.Empty); - } - } - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoPassportViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoPassportViewModel.cs index d44e0a61..3833ad71 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoPassportViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoPassportViewModel.cs @@ -1,12 +1,14 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using CommunityToolkit.Common; using Snap.Hutao.Core.Setting; using Snap.Hutao.Service.Hutao; using Snap.Hutao.Service.Navigation; using Snap.Hutao.Service.Notification; using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Response; +using System.Text.RegularExpressions; namespace Snap.Hutao.ViewModel; @@ -17,9 +19,12 @@ namespace Snap.Hutao.ViewModel; [Injection(InjectAs.Scoped)] internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel { - private readonly IServiceProvider serviceProvider; - private readonly ITaskContext taskContext; private readonly HomaPassportClient homaPassportClient; + private readonly INavigationService navigationService; + private readonly HutaoUserOptions hutaoUserOptions; + private readonly IServiceProvider serviceProvider; + private readonly IInfoBarService infoBarService; + private readonly ITaskContext taskContext; private string? userName; private string? password; @@ -40,22 +45,16 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel /// public string? VerifyCode { get => verifyCode; set => SetProperty(ref verifyCode, value); } - /// - protected override Task OpenUIAsync() - { - return Task.CompletedTask; - } - [Command("RegisterVerifyCommand")] private Task RegisterVerifyAsync() { - return VerifyAsync(false); + return VerifyAsync(false).AsTask(); } [Command("RegisterCommand")] private async Task RegisterAsync() { - if (UserName == null || Password == null || VerifyCode == null) + if (UserName is null || Password is null || VerifyCode is null) { return; } @@ -65,13 +64,12 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel if (response.IsOk()) { SaveUserNameAndPassword(); - serviceProvider.GetRequiredService().Information(response.Message); + infoBarService.Information(response.Message); await taskContext.SwitchToMainThreadAsync(); - serviceProvider.GetRequiredService().LoginSucceed(UserName, response.Data); + hutaoUserOptions.LoginSucceed(UserName, response.Data); - await serviceProvider - .GetRequiredService() + await navigationService .NavigateAsync(INavigationAwaiter.Default, true) .ConfigureAwait(false); } @@ -80,13 +78,13 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel [Command("ResetPasswordVerifyCommand")] private Task ResetPasswordVerifyAsync() { - return VerifyAsync(true); + return VerifyAsync(true).AsTask(); } [Command("ResetPasswordCommand")] private async Task ResetPasswordAsync() { - if (UserName == null || Password == null || VerifyCode == null) + if (UserName is null || Password is null || VerifyCode is null) { return; } @@ -96,13 +94,12 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel if (response.IsOk()) { SaveUserNameAndPassword(); - serviceProvider.GetRequiredService().Information(response.Message); + infoBarService.Information(response.Message); await taskContext.SwitchToMainThreadAsync(); - serviceProvider.GetRequiredService().LoginSucceed(UserName, response.Data); + hutaoUserOptions.LoginSucceed(UserName, response.Data); - await serviceProvider - .GetRequiredService() + await navigationService .NavigateAsync(INavigationAwaiter.Default, true) .ConfigureAwait(false); } @@ -111,7 +108,7 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel [Command("LoginCommand")] private async Task LoginAsync() { - if (UserName == null || Password == null) + if (UserName is null || Password is null) { return; } @@ -121,32 +118,36 @@ internal sealed partial class HutaoPassportViewModel : Abstraction.ViewModel if (response.IsOk()) { SaveUserNameAndPassword(); - serviceProvider.GetRequiredService().Information(response.Message); + infoBarService.Information(response.Message); await taskContext.SwitchToMainThreadAsync(); - serviceProvider.GetRequiredService().LoginSucceed(UserName, response.Data); + hutaoUserOptions.LoginSucceed(UserName, response.Data); - await serviceProvider - .GetRequiredService() + await navigationService .NavigateAsync(INavigationAwaiter.Default, true) .ConfigureAwait(false); } } - private async Task VerifyAsync(bool isResetPassword) + private async ValueTask VerifyAsync(bool isResetPassword) { - if (UserName == null) + if (string.IsNullOrEmpty(UserName)) { return; } + if (!UserName.IsEmail()) + { + infoBarService.Warning(SH.ViewModelHutaoPassportEmailNotValidHint); + } + Response response = await homaPassportClient.VerifyAsync(UserName, isResetPassword).ConfigureAwait(false); serviceProvider.GetRequiredService().Information(response.Message); } private void SaveUserNameAndPassword() { - if (UserName != null && Password != null) + if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) { LocalSetting.Set(SettingKeys.PassportUserName, UserName); LocalSetting.Set(SettingKeys.PassportPassword, Password); diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs index 3fc8d36a..1fc4e9b5 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs @@ -1,11 +1,12 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Microsoft.EntityFrameworkCore; +using Microsoft.UI.Xaml.Controls; using Microsoft.Windows.AppLifecycle; using Snap.Hutao.Core; using Snap.Hutao.Core.IO; using Snap.Hutao.Core.IO.DataTransfer; -using Snap.Hutao.Core.LifeCycle; using Snap.Hutao.Core.Setting; using Snap.Hutao.Core.Windowing; using Snap.Hutao.Factory.Abstraction; @@ -13,7 +14,6 @@ using Snap.Hutao.Model; using Snap.Hutao.Model.Entity.Database; using Snap.Hutao.Service; using Snap.Hutao.Service.GachaLog.QueryProvider; -using Snap.Hutao.Service.Game; using Snap.Hutao.Service.Game.Locator; using Snap.Hutao.Service.Hutao; using Snap.Hutao.Service.Navigation; @@ -22,6 +22,7 @@ using Snap.Hutao.View.Dialog; using System.Globalization; using System.IO; using System.Runtime.InteropServices; +using Windows.System; namespace Snap.Hutao.ViewModel; @@ -35,13 +36,9 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel { private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; - private readonly AppDbContext appDbContext; - private readonly IGameService gameService; - private readonly ILogger logger; private readonly AppOptions options; - private readonly RuntimeOptions hutaoOptions; + private readonly RuntimeOptions runtimeOptions; private readonly HutaoUserOptions hutaoUserOptions; - private readonly ExperimentalFeaturesViewModel experimental; private NameValue? selectedBackdropType; private NameValue? selectedCulture; @@ -54,7 +51,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel /// /// 胡桃选项 /// - public RuntimeOptions HutaoOptions { get => hutaoOptions; } + public RuntimeOptions HutaoOptions { get => runtimeOptions; } /// /// 胡桃用户选项 @@ -95,11 +92,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel } } - /// - /// 实验性功能 - /// - public ExperimentalFeaturesViewModel Experimental { get => experimental; } - /// protected override Task OpenUIAsync() { @@ -216,4 +208,36 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel { serviceProvider.GetRequiredService().Navigate(INavigationAwaiter.Default); } + + [Command("OpenCacheFolderCommand")] + private Task OpenCacheFolderAsync() + { + return Launcher.LaunchFolderPathAsync(runtimeOptions.LocalCache).AsTask(); + } + + [Command("OpenDataFolderCommand")] + private Task OpenDataFolderAsync() + { + return Launcher.LaunchFolderPathAsync(runtimeOptions.DataFolder).AsTask(); + } + + [Command("DeleteUsersCommand")] + private async Task DangerousDeleteUsersAsync() + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + ContentDialogResult result = await scope.ServiceProvider + .GetRequiredService() + .CreateForConfirmCancelAsync(SH.ViewDialogSettingDeleteUserDataTitle, SH.ViewDialogSettingDeleteUserDataContent) + .ConfigureAwait(false); + + if (result == ContentDialogResult.Primary) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.Users.ExecuteDeleteAsync().ConfigureAwait(false); + + AppInstance.Restart(string.Empty); + } + } + } } \ No newline at end of file