bulk refactor

This commit is contained in:
DismissedLight
2023-11-15 22:31:56 +08:00
parent 3e0493be31
commit 98f2dd13d1
43 changed files with 187 additions and 128 deletions

View File

@@ -140,6 +140,8 @@ internal sealed class AttributeGenerator : IIncrementalGenerator
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
{
}
public object Key { get; set; }
}
""";
context.AddSource("Snap.Hutao.Core.DependencyInjection.Annotation.Attributes.g.cs", coreDependencyInjectionAnnotations);

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Snap.Hutao.SourceGeneration.Primitive;
using System.Collections.Generic;
@@ -68,7 +69,7 @@ internal sealed class DependencyPropertyGenerator : IIncrementalGenerator
string propertyName = (string)arguments[0].Value!;
string propertyType = arguments[1].Value!.ToString();
string defaultValue = GetLiteralString(arguments.ElementAtOrDefault(2)) ?? "default";
string defaultValue = arguments.ElementAtOrDefault(2).ToCSharpString() ?? "default";
string propertyChangedCallback = arguments.ElementAtOrDefault(3) is { IsNull: false } arg3 ? $", {arg3.Value}" : string.Empty;
string code;
@@ -125,25 +126,4 @@ internal sealed class DependencyPropertyGenerator : IIncrementalGenerator
production.AddSource($"{normalizedClassName}.{propertyName}.g.cs", code);
}
}
private static string? GetLiteralString(TypedConstant typedConstant)
{
if (typedConstant.IsNull)
{
return default;
}
if (typedConstant.Value is bool boolValue)
{
return boolValue ? "true" : "false";
}
string result = typedConstant.Value!.ToString();
if (string.IsNullOrEmpty(result))
{
return default;
}
return result;
}
}

View File

@@ -92,17 +92,29 @@ internal sealed class InjectionGenerator : IIncrementalGenerator
ImmutableArray<TypedConstant> arguments = injectionInfo.ConstructorArguments;
string injectAsName = arguments[0].ToCSharpString();
switch (injectAsName)
bool hasKey = injectionInfo.TryGetNamedArgumentValue("Key", out TypedConstant key);
switch (injectAsName, hasKey)
{
case InjectAsSingletonName:
case (InjectAsSingletonName, false):
lineBuilder.Append(" services.AddSingleton<");
break;
case InjectAsTransientName:
case (InjectAsSingletonName, true):
lineBuilder.Append(" services.AddKeyedSingleton<");
break;
case (InjectAsTransientName, false):
lineBuilder.Append(" services.AddTransient<");
break;
case InjectAsScopedName:
case (InjectAsTransientName, true):
lineBuilder.Append(" services.AddKeyedTransient<");
break;
case (InjectAsScopedName, false):
lineBuilder.Append(" services.AddScoped<");
break;
case (InjectAsScopedName, true):
lineBuilder.Append(" services.AddKeyedScoped<");
break;
default:
production.ReportDiagnostic(Diagnostic.Create(invalidInjectionDescriptor, context.Context.Node.GetLocation(), injectAsName));
break;
@@ -113,7 +125,14 @@ internal sealed class InjectionGenerator : IIncrementalGenerator
lineBuilder.Append($"{arguments[1].Value}, ");
}
lineBuilder.Append($"{context.Symbol.ToDisplayString()}>();");
if (hasKey)
{
lineBuilder.Append($"{context.Symbol.ToDisplayString()}>({key.ToCSharpString()});");
}
else
{
lineBuilder.Append($"{context.Symbol.ToDisplayString()}>();");
}
lines.Add(lineBuilder.ToString());
}

View File

@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Snap.Hutao.SourceGeneration.Primitive;
@@ -13,4 +14,19 @@ internal static class AttributeDataExtension
{
return data.NamedArguments.Any(a => a.Key == key && predicate((TValue)a.Value.Value!));
}
public static bool TryGetNamedArgumentValue(this AttributeData data, string key, out TypedConstant value)
{
foreach (KeyValuePair<string, TypedConstant> pair in data.NamedArguments)
{
if (pair.Key == key)
{
value = pair.Value;
return true;
}
}
value = default;
return false;
}
}

View File

@@ -8,6 +8,7 @@
<Platforms>x64</Platforms>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<Configurations>Debug;Release</Configurations>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>

View File

@@ -7,6 +7,10 @@ namespace Snap.Hutao.Test;
[TestClass]
public class JsonSerializeTest
{
private TestContext? testContext;
public TestContext? TestContext { get => testContext; set => testContext = value; }
private readonly JsonSerializerOptions AlowStringNumberOptions = new()
{
NumberHandling = JsonNumberHandling.AllowReadingFromString,
@@ -53,6 +57,27 @@ public class JsonSerializeTest
Assert.AreEqual(sample[111], "12");
}
[TestMethod]
public void ByteArraySerializeAsBase64()
{
byte[] array =
#if NET8_0_OR_GREATER
[1, 2, 3, 4, 5];
#else
{ 1, 2, 3, 4, 5 };
#endif
ByteArraySample sample = new()
{
Array = array,
};
string result = JsonSerializer.Serialize(sample);
TestContext!.WriteLine($"ByteArray Serialize Result: {result}");
Assert.AreEqual(result, """
{"Array":"AQIDBAU="}
""");
}
private sealed class Sample
{
public int A { get => B; set => B = value; }
@@ -64,4 +89,9 @@ public class JsonSerializeTest
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int A { get; set; }
}
private sealed class ByteArraySample
{
public byte[]? Array { get; set; }
}
}

View File

@@ -9,8 +9,12 @@ public sealed class ForEachRuntimeBehaviorTest
[TestMethod]
public void ListOfStringCanEnumerateAsReadOnlySpanOfChar()
{
List<string> strings = ["a", "b", "c"];
List<string> strings =
#if NET8_0_OR_GREATER
["a", "b", "c"];
#else
new() { "a", "b", "c" };
#endif
int count = 0;
foreach (ReadOnlySpan<char> chars in strings)
{

View File

@@ -8,8 +8,13 @@ public sealed class RangeRuntimeBehaviorTest
[TestMethod]
public void RangeTrimLastOne()
{
#if NET8_0_OR_GREATER
int[] array = [1, 2, 3, 4];
int[] test = [1, 2, 3];
#else
int[] array = { 1, 2, 3, 4 };
int[] test = { 1, 2, 3 };
#endif
int[] result = array[..^1];
Assert.AreEqual(3, result.Length);
Assert.IsTrue(MemoryExtensions.SequenceEqual<int>(test, result));

View File

@@ -6,7 +6,12 @@ public sealed class UnsafeRuntimeBehaviorTest
[TestMethod]
public unsafe void UInt32AllSetIs()
{
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF,];
byte[] bytes =
#if NET8_0_OR_GREATER
[0xFF, 0xFF, 0xFF, 0xFF];
#else
{ 0xFF, 0xFF, 0xFF, 0xFF, };
#endif
fixed (byte* pBytes = bytes)
{

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>

View File

@@ -35,7 +35,6 @@ internal static class DependencyInjection
// Discrete services
.AddSingleton<IMessenger, WeakReferenceMessenger>()
.BuildServiceProvider(true);
Ioc.Default.ConfigureServices(serviceProvider);

View File

@@ -48,7 +48,7 @@ internal sealed partial class GameChannelOptionsService : IGameChannelOptionsSer
{
using (FileStream readStream = File.OpenRead(configPath))
{
elements = IniSerializer.Deserialize(readStream).ToList();
elements = [.. IniSerializer.Deserialize(readStream)];
}
}
catch (FileNotFoundException ex)

View File

@@ -165,11 +165,11 @@ internal sealed class LaunchOptions : DbStoreOptions
set => SetOption(ref isMonitorEnabled, SettingEntry.LaunchIsMonitorEnabled, value);
}
public List<AspectRatio> AspectRatios { get; } = new()
{
public List<AspectRatio> AspectRatios { get; } =
[
new(2560, 1440),
new(1920, 1080),
};
];
public AspectRatio? SelectedAspectRatio
{

View File

@@ -178,11 +178,11 @@ internal sealed partial class PackageConverter
private async ValueTask<Dictionary<string, VersionItem>> GetVersionItemsAsync(Stream stream)
{
Dictionary<string, VersionItem> results = new();
Dictionary<string, VersionItem> results = [];
using (StreamReader reader = new(stream))
{
Regex dataFolderRegex = DataFolderRegex();
while (await reader.ReadLineAsync().ConfigureAwait(false) is { } row && !string.IsNullOrEmpty(row))
while (await reader.ReadLineAsync().ConfigureAwait(false) is { Length: > 0 } row)
{
VersionItem? item = JsonSerializer.Deserialize<VersionItem>(row, options);
ArgumentNullException.ThrowIfNull(item);

View File

@@ -30,8 +30,8 @@ internal sealed partial class GameProcessService : IGameProcessService
return false;
}
return System.Diagnostics.Process.GetProcessesByName(YuanShenProcessName).Any()
|| System.Diagnostics.Process.GetProcessesByName(GenshinImpactProcessName).Any();
return System.Diagnostics.Process.GetProcessesByName(YuanShenProcessName).Length > 0
|| System.Diagnostics.Process.GetProcessesByName(GenshinImpactProcessName).Length > 0;
}
public async ValueTask LaunchAsync(IProgress<LaunchStatus> progress)
@@ -126,7 +126,9 @@ internal sealed partial class GameProcessService : IGameProcessService
private ValueTask UnlockFpsAsync(System.Diagnostics.Process game, IProgress<LaunchStatus> progress, CancellationToken token = default)
{
#pragma warning disable CA1859
IGameFpsUnlocker unlocker = serviceProvider.CreateInstance<GameFpsUnlocker>(game);
#pragma warning restore CA1859
UnlockTimingOptions options = new(100, 20000, 3000);
Progress<UnlockerStatus> lockerProgress = new(unlockStatus => progress.Report(LaunchStatus.FromUnlockStatus(unlockStatus)));
return unlocker.UnlockAsync(options, lockerProgress, token);

View File

@@ -28,8 +28,9 @@ internal static class KnownLaunchSchemes
/// <returns>已知的启动方案</returns>
public static List<LaunchScheme> Get()
{
return new List<LaunchScheme>()
{
return
[
// 官服
ServerChineseChannelDefaultSubChannelDefaultCompat,
ServerChineseChannelOfficialSubChannelDefault,
@@ -47,6 +48,6 @@ internal static class KnownLaunchSchemes
ServerGlobalChannelOfficialSubChannelOfficial,
ServerGlobalChannelOfficialSubChannelEpic,
ServerGlobalChannelOfficialSubChannelGoogle,
};
];
}
}

View File

@@ -135,8 +135,8 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker
{
// E8 ?? ?? ?? ?? 85 C0 7E 07 E8 ?? ?? ?? ?? EB 05
int second = 0;
ReadOnlySpan<byte> secondPart = stackalloc byte[] { 0x85, 0xC0, 0x7E, 0x07, 0xE8, };
ReadOnlySpan<byte> thirdPart = stackalloc byte[] { 0xEB, 0x05, };
ReadOnlySpan<byte> secondPart = [0x85, 0xC0, 0x7E, 0x07, 0xE8,];
ReadOnlySpan<byte> thirdPart = [0xEB, 0x05,];
while (second >= 0 && second < memory.Length)
{

View File

@@ -39,7 +39,7 @@ internal sealed partial class HutaoAsAService : IHutaoAsAService
}
else
{
return new();
return [];
}
}

View File

@@ -168,6 +168,23 @@ internal sealed class NavigationService : INavigationService, INavigationInitial
});
}
private static IEnumerable<NavigationViewItem> EnumerateMenuItems(IList<object> items)
{
foreach (NavigationViewItem item in items.OfType<NavigationViewItem>())
{
yield return item;
// Suppress recursion method call if possible
if (item.MenuItems.Count > 0)
{
foreach (NavigationViewItem subItem in EnumerateMenuItems(item.MenuItems))
{
yield return subItem;
}
}
}
}
private bool SyncSelectedNavigationViewItemWith(Type? pageType)
{
if (NavigationView is null || pageType is null)
@@ -191,23 +208,6 @@ internal sealed class NavigationService : INavigationService, INavigationInitial
return true;
}
private IEnumerable<NavigationViewItem> EnumerateMenuItems(IList<object> items)
{
foreach (NavigationViewItem item in items.OfType<NavigationViewItem>())
{
yield return item;
// Suppress recursion method call if possible
if (item.MenuItems.Count > 0)
{
foreach (NavigationViewItem subItem in EnumerateMenuItems(item.MenuItems))
{
yield return subItem;
}
}
}
}
private void OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
selected = NavigationView?.SelectedItem as NavigationViewItem;

View File

@@ -31,7 +31,7 @@ internal sealed class InfoBarService : IInfoBarService
/// <inheritdoc/>
public ObservableCollection<InfoBar> Collection
{
get => collection ??= new();
get => collection ??= [];
}
/// <inheritdoc/>
@@ -121,7 +121,7 @@ internal sealed class InfoBarService : IInfoBarService
Title = title,
Message = message,
IsOpen = true,
Transitions = new() { new AddDeleteThemeTransition() },
Transitions = [new AddDeleteThemeTransition()],
};
infoBar.Closed += infobarClosedEventHandler;

View File

@@ -24,7 +24,7 @@ internal sealed partial class UserInitializationService : IUserInitializationSer
if (!await InitializeUserAsync(user, token).ConfigureAwait(false))
{
user.UserInfo = new() { Nickname = SH.ModelBindingUserInitializationFailed };
user.UserGameRoles = new();
user.UserGameRoles = [];
}
return user;
@@ -176,7 +176,7 @@ internal sealed partial class UserInitializationService : IUserInitializationSer
if (userGameRolesResponse.IsOk())
{
user.UserGameRoles = userGameRolesResponse.Data.List;
return user.UserGameRoles.Any();
return user.UserGameRoles.Count > 0;
}
else
{

View File

@@ -271,22 +271,22 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.13">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231008000" />
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.507">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>

View File

@@ -252,7 +252,6 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
}
}
[SuppressMessage("", "SA1010")]
[Command("ExportAsUIAFToFileCommand")]
private async Task ExportAsUIAFToFileAsync()
{

View File

@@ -23,8 +23,7 @@ internal sealed class Team : List<AvatarView>
public Team(ItemRate<string, int> team, Dictionary<AvatarId, Avatar> idAvatarMap)
: base(4)
{
// TODO use Collection Literials
foreach (StringSegment item in new StringTokenizer(team.Item, new char[] { ',' }))
foreach (StringSegment item in new StringTokenizer(team.Item, [',']))
{
uint id = uint.Parse(item.AsSpan(), CultureInfo.InvariantCulture);
Add(new(idAvatarMap[id]));

View File

@@ -38,7 +38,7 @@ internal sealed partial class DailyNoteViewModelSlim : Abstraction.ViewModelSlim
// 此处使用浅拷贝的列表以避免当导航到实时便笺页面后
// 由于主页尚未卸载,添加或删除便笺可能会崩溃的问题
List<DailyNoteEntry> entryList = entries.ToList();
List<DailyNoteEntry> entryList = [.. entries];
await taskContext.SwitchToMainThreadAsync();
DailyNoteEntries = entryList;

View File

@@ -231,7 +231,6 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
}
}
[SuppressMessage("", "SA1010")]
[Command("ExportToUIGFJsonCommand")]
private async Task ExportToUIGFJsonAsync()
{

View File

@@ -109,7 +109,7 @@ internal static class StaticResource
public static HashSet<string> GetUnfulfilledCategorySet()
{
HashSet<string> result = new();
HashSet<string> result = [];
ApplicationDataCompositeValue map = LocalSetting.Get(ContractMap, DefaultResourceVersionMap);
foreach ((string key, object value) in LatestResourceVersionMap)
{

View File

@@ -230,15 +230,15 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
}
[Command("OpenCacheFolderCommand")]
private Task OpenCacheFolderAsync()
private async Task OpenCacheFolderAsync()
{
return Launcher.LaunchFolderPathAsync(runtimeOptions.LocalCache).AsTask();
await Launcher.LaunchFolderPathAsync(runtimeOptions.LocalCache);
}
[Command("OpenDataFolderCommand")]
private Task OpenDataFolderAsync()
private async Task OpenDataFolderAsync()
{
return Launcher.LaunchFolderPathAsync(runtimeOptions.DataFolder).AsTask();
await Launcher.LaunchFolderPathAsync(runtimeOptions.DataFolder);
}
[Command("DeleteUsersCommand")]

View File

@@ -16,11 +16,7 @@ internal sealed class LevelView : IMappingFrom<LevelView, TowerLevel, SpiralAbys
{
Index = SH.ModelBindingHutaoComplexRankLevel.Format(towerLevel.Index);
IndexValue = towerLevel.Index;
Battles = new()
{
BattleView.From(towerLevel, 1, context),
BattleView.From(towerLevel, 2, context),
};
Battles = [BattleView.From(towerLevel, 1, context), BattleView.From(towerLevel, 2, context)];
}
/// <summary>

View File

@@ -24,10 +24,8 @@ internal static class AvatarFilter
private static bool DoFilter(string input, Avatar avatar)
{
List<bool> matches = new();
// TODO: use Collection Literals
foreach (StringSegment segment in new StringTokenizer(input, new char[] { ' ' }))
List<bool> matches = [];
foreach (StringSegment segment in new StringTokenizer(input, [' ']))
{
string value = segment.ToString();

View File

@@ -22,7 +22,6 @@ internal static class WeaponFilter
return (object o) => o is Weapon weapon && DoFilter(input, weapon);
}
[SuppressMessage("", "SA1010")]
private static bool DoFilter(string input, Weapon weapon)
{
List<bool> matches = [];

View File

@@ -92,15 +92,15 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
List<Avatar> avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false);
List<Avatar> sorted = avatars
IOrderedEnumerable<Avatar> sorted = avatars
.OrderByDescending(avatar => avatar.BeginTime)
.ThenByDescending(avatar => avatar.Sort)
.ToList();
.ThenByDescending(avatar => avatar.Sort);
List<Avatar> list = [.. sorted];
await CombineComplexDataAsync(sorted, idMaterialMap).ConfigureAwait(false);
await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
Avatars = new AdvancedCollectionView(sorted, true);
Avatars = new AdvancedCollectionView(list, true);
Selected = Avatars.Cast<Avatar>().FirstOrDefault();
return true;
}
@@ -192,13 +192,13 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
Dictionary<FightProperty, GrowCurveType> avatarGrowCurve = avatar.GrowCurves.ToDictionary(g => g.Type, g => g.Value);
FightProperty promoteProperty = avatarPromoteMap[0].AddProperties.Last().Type;
List<PropertyCurveValue> propertyCurveValues = new()
{
List<PropertyCurveValue> propertyCurveValues =
[
new(FightProperty.FIGHT_PROP_BASE_HP, avatarGrowCurve, avatar.BaseValue),
new(FightProperty.FIGHT_PROP_BASE_ATTACK, avatarGrowCurve, avatar.BaseValue),
new(FightProperty.FIGHT_PROP_BASE_DEFENSE, avatarGrowCurve, avatar.BaseValue),
new(promoteProperty, avatarGrowCurve, avatar.BaseValue),
};
];
ArgumentNullException.ThrowIfNull(levelAvatarCurveMap);
BaseValueInfo = new(avatar.MaxLevel, propertyCurveValues, levelAvatarCurveMap, avatarPromoteMap);

View File

@@ -461,7 +461,7 @@ internal class MiHoYoJSBridge
}
[SuppressMessage("", "CA2254")]
private IJsResult? LogUnhandledMessage([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string message, params object?[] param)
private IJsResult? LogUnhandledMessage(string message, params object?[] param)
{
logger.LogWarning(message, param);
return default;
@@ -490,7 +490,7 @@ internal class MiHoYoJSBridge
"pushPage" => await PushPageAsync(param).ConfigureAwait(false),
"share" => Share(param),
"showLoading" => null,
_ => LogUnhandledMessage("Unhandled Message Type: {method}", param.Method),
_ => LogUnhandledMessage("Unhandled Message Type: {Method}", param.Method),
};
}
catch (ObjectDisposedException)

View File

@@ -18,7 +18,7 @@ internal sealed partial class Cookie
/// 构造一个空白的Cookie
/// </summary>
public Cookie()
: this(new())
: this([])
{
}
@@ -44,7 +44,7 @@ internal sealed partial class Cookie
/// <returns>新的Cookie对象</returns>
public static Cookie Parse(string cookieString)
{
SortedDictionary<string, string> cookieMap = new();
SortedDictionary<string, string> cookieMap = [];
cookieString = cookieString.Replace(" ", string.Empty, StringComparison.Ordinal);
string[] values = cookieString.Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (string[] parts in values.Select(c => c.Split('=', 2)))
@@ -59,7 +59,7 @@ internal sealed partial class Cookie
public static Cookie FromCoreWebView2Cookies(IReadOnlyList<CoreWebView2Cookie> webView2Cookies)
{
SortedDictionary<string, string> cookieMap = new();
SortedDictionary<string, string> cookieMap = [];
foreach (CoreWebView2Cookie cookie in webView2Cookies)
{

View File

@@ -8,7 +8,6 @@ namespace Snap.Hutao.Web.Hoyolab;
internal static class PlayerUidExtension
{
[SuppressMessage("", "SA1010")]
public static string ToQueryString(this in PlayerUid playerUid)
{
NameValueCollection collection = [];

View File

@@ -53,12 +53,12 @@ internal sealed class AvatarPromotionDelta
return new()
{
AvatarLevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarLevelTarget, 90U),
SkillList = new()
{
SkillList =
[
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillATarget, 10U), },
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillETarget, 10U), },
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillQTarget, 10U), },
},
],
Weapon = new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationWeapon90LevelTarget, 90U), },
};
}

View File

@@ -57,7 +57,7 @@ internal sealed partial class CalculateClient
int currentPage = 1;
SyncAvatarFilter filter = new() { Uid = userAndUid.Uid.Value, Region = userAndUid.Uid.Region };
List<Avatar> avatars = new();
List<Avatar> avatars = [];
Response<ListWrapper<Avatar>>? resp;
do
@@ -166,10 +166,10 @@ internal sealed partial class CalculateClient
private class SyncAvatarFilter
{
[JsonPropertyName("element_attr_ids")]
public List<int>? ElementAttrIds { get; set; } = new();
public List<int>? ElementAttrIds { get; set; } = [];
[JsonPropertyName("weapon_cat_ids")]
public List<int>? WeaponCatIds { get; set; } = new();
public List<int>? WeaponCatIds { get; set; } = [];
[JsonPropertyName("page")]
public int Page { get; set; }

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Frozen;
using System.Collections.Immutable;
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
@@ -17,10 +18,7 @@ internal sealed class Expedition
private const string Keqing = "https://upload-bbs.mihoyo.com/game_record/genshin/character_side_icon/UI_AvatarIcon_Side_Keqing.png";
private const string Sara = "https://upload-bbs.mihoyo.com/game_record/genshin/character_side_icon/UI_AvatarIcon_Side_Sara.png";
private static readonly ImmutableList<string> ShortExpeditionTimeAvatars = new List<string>()
{
Bennett, Chongyun, Fischl, Keqing, Sara,
}.ToImmutableList();
private static readonly FrozenSet<string> ShortExpeditionTimeAvatars = FrozenSet.ToFrozenSet([Bennett, Chongyun, Fischl, Keqing, Sara]);
/// <summary>
/// 图标

View File

@@ -53,7 +53,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
{
// Replace message
resp.Message = SH.WebDailyNoteVerificationFailed;
IGeetestCardVerifier verifier = serviceProvider.GetRequiredService<HomaGeetestCardVerifier>();
IGeetestCardVerifier verifier = serviceProvider.GetRequiredKeyedService<IGeetestCardVerifier>(GeetestCardVerifierType.Custom);
if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
{
@@ -99,7 +99,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
{
// Replace message
resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
IGeetestCardVerifier verifier = serviceProvider.GetRequiredService<HomaGeetestCardVerifier>();
IGeetestCardVerifier verifier = serviceProvider.GetRequiredKeyedService<IGeetestCardVerifier>(GeetestCardVerifierType.Custom);
if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
{
@@ -146,7 +146,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
{
// Replace message
resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
IGeetestCardVerifier verifier = serviceProvider.GetRequiredService<HomaGeetestCardVerifier>();
IGeetestCardVerifier verifier = serviceProvider.GetRequiredKeyedService<IGeetestCardVerifier>(GeetestCardVerifierType.Custom);
if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
{
@@ -156,9 +156,9 @@ internal sealed partial class GameRecordClient : IGameRecordClient
.SetXrpcChallenge(challenge)
.Get();
await builder.SetDynamicSecretAsync(DynamicSecretVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
await verifiedbuilder.SetDynamicSecretAsync(DynamicSecretVersion.Gen2, SaltType.X4, false).ConfigureAwait(false);
resp = await builder
resp = await verifiedbuilder
.TryCatchSendAsync<Response<SpiralAbyss.SpiralAbyss>>(httpClient, logger, token)
.ConfigureAwait(false);
}
@@ -216,7 +216,7 @@ internal sealed partial class GameRecordClient : IGameRecordClient
{
// Replace message
resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
IGeetestCardVerifier verifier = serviceProvider.GetRequiredService<HomaGeetestCardVerifier>();
IGeetestCardVerifier verifier = serviceProvider.GetRequiredKeyedService<IGeetestCardVerifier>(GeetestCardVerifierType.Custom);
if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
{

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Verification;
internal enum GeetestCardVerifierType
{
Custom,
}

View File

@@ -7,7 +7,7 @@ using Snap.Hutao.Web.Hutao.Geetest;
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Verification;
[ConstructorGenerated]
[Injection(InjectAs.Transient)]
[Injection(InjectAs.Transient, Key = GeetestCardVerifierType.Custom)]
internal sealed partial class HomaGeetestCardVerifier : IGeetestCardVerifier
{
private readonly CardClient cardClient;

View File

@@ -14,7 +14,6 @@ internal sealed class ReliquarySetsConverter : JsonConverter<ReliquarySets>
private const char Separator = ',';
/// <inheritdoc/>
[SuppressMessage("", "SA1010")]
public override ReliquarySets? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.GetString() is { } source)

View File

@@ -62,7 +62,7 @@ internal class JsonHttpContentSerializer : HttpContentSerializer
return JsonSerializer.Deserialize(json, contentType, JsonSerializerOptions);
}
private HttpContent? SerializeUtf8(object? content, Type contentType)
private ByteArrayContent? SerializeUtf8(object? content, Type contentType)
{
byte[] bytes = JsonSerializer.SerializeToUtf8Bytes(content, contentType, JsonSerializerOptions);
ByteArrayContent httpContent = new(bytes);
@@ -75,7 +75,7 @@ internal class JsonHttpContentSerializer : HttpContentSerializer
return httpContent;
}
private HttpContent? SerializeOtherEncoding(object? content, Type contentType, Encoding encoding)
private StringContent? SerializeOtherEncoding(object? content, Type contentType, Encoding encoding)
{
string str = JsonSerializer.Serialize(content, contentType, JsonSerializerOptions);
return new StringContent(str, encoding, MediaType.ApplicationJson);