remove async relay command factory

This commit is contained in:
DismissedLight
2023-01-18 15:29:22 +08:00
parent da0ee0cca6
commit ca56d8c636
55 changed files with 301 additions and 541 deletions

View File

@@ -43,8 +43,8 @@
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
<!-- OpenPaneLength -->
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
<x:Double x:Key="CompatSplitViewOpenPaneLength2">252</x:Double>
<GridLength x:Key="CompatGridLength2">252</GridLength>
<x:Double x:Key="CompatSplitViewOpenPaneLength2">268</x:Double>
<GridLength x:Key="CompatGridLength2">268</GridLength>
<!-- Uris -->
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-cookie</x:String>
<x:String x:Key="DocumentLink_BugReport">https://hut.ao/statements/bug-report.html</x:String>

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.WinUI.Notifications;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;

View File

@@ -0,0 +1,57 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Windows.Foundation;
namespace Snap.Hutao.Control.Panel;
/// <summary>
/// 纵横比控件
/// </summary>
internal class AspectRatio : Microsoft.UI.Xaml.Controls.ContentControl
{
private static readonly DependencyProperty TargetWidthProperty = Property<AspectRatio>.Depend(nameof(TargetWidth), 1D);
private static readonly DependencyProperty TargetHeightProperty = Property<AspectRatio>.Depend(nameof(TargetHeight), 1D);
/// <summary>
/// 目标宽度
/// </summary>
public double TargetWidth
{
get => (double)GetValue(TargetWidthProperty);
set => SetValue(TargetWidthProperty, value);
}
/// <summary>
/// 目标高度
/// </summary>
public double TargetHeight
{
get => (double)GetValue(TargetHeightProperty);
set => SetValue(TargetHeightProperty, value);
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
double ratio = TargetWidth / TargetHeight;
double ratioAvailable = availableSize.Width / availableSize.Height;
// 更宽
if (ratioAvailable > ratio)
{
double newWidth = ratio * availableSize.Height;
return new Size(newWidth, availableSize.Height);
}
// 更高
else if (ratioAvailable < ratio)
{
double newHeight = availableSize.Width / ratio;
return new Size(availableSize.Width, newHeight);
}
return availableSize;
}
}

View File

@@ -16,7 +16,7 @@ namespace Snap.Hutao.Control;
[SuppressMessage("", "CA1001")]
public class ScopedPage : Page
{
private readonly CancellationTokenSource viewLoadingCancellationTokenSource = new();
private readonly CancellationTokenSource viewCancellationTokenSource = new();
private readonly IServiceScope serviceScope;
/// <summary>
@@ -37,7 +37,7 @@ public class ScopedPage : Page
where TViewModel : class, IViewModel
{
IViewModel viewModel = serviceScope.ServiceProvider.GetRequiredService<TViewModel>();
viewModel.CancellationToken = viewLoadingCancellationTokenSource.Token;
viewModel.CancellationToken = viewCancellationTokenSource.Token;
DataContext = viewModel;
}
@@ -60,10 +60,10 @@ public class ScopedPage : Page
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
using (viewLoadingCancellationTokenSource)
using (viewCancellationTokenSource)
{
// Cancel tasks executed by the view model
viewLoadingCancellationTokenSource.Cancel();
// Cancel all tasks executed by the view model
viewCancellationTokenSource.Cancel();
IViewModel viewModel = (IViewModel)DataContext;
using (SemaphoreSlim locker = viewModel.DisposeLock)
@@ -79,14 +79,13 @@ public class ScopedPage : Page
}
/// <inheritdoc/>
[SuppressMessage("", "VSTHRD100")]
protected override async void OnNavigatedTo(NavigationEventArgs e)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.Parameter is INavigationData extra)
{
await NotifyRecipentAsync(extra).ConfigureAwait(false);
NotifyRecipentAsync(extra).SafeForget();
}
}
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Abstraction;
/// <summary>
/// 可异步初始化
/// </summary>
internal interface ISupportAsyncInitialization
{
/// <summary>
/// 是否已经初始化完成
/// </summary>
public bool IsInitialized { get; }
/// <summary>
/// 异步初始化
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>初始化任务</returns>
ValueTask<bool> InitializeAsync();
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Abstraction;
/// <summary>
/// 表示支持验证
/// </summary>
internal interface ISupportValidation
{
/// <summary>
/// 验证
/// </summary>
/// <returns>当前数据是否有效</returns>
public bool Validate();
}

View File

@@ -25,7 +25,7 @@ public class ImageCache : IImageCache, IImageCacheFilePathOperation
{
private const string CacheFolderName = nameof(ImageCache);
private static readonly Dictionary<int, TimeSpan> RetryCountToDelay = new Dictionary<int, TimeSpan>()
private static readonly Dictionary<int, TimeSpan> RetryCountToDelay = new()
{
[0] = TimeSpan.FromSeconds(4),
[1] = TimeSpan.FromSeconds(16),

View File

@@ -4,19 +4,19 @@
using System.Security.Cryptography;
using System.Text;
namespace Snap.Hutao.Core.Convert;
namespace Snap.Hutao.Core;
/// <summary>
/// 支持Md5转换
/// </summary>
internal abstract class Md5Convert
internal static class Convert
{
/// <summary>
/// 获取字符串的MD5计算结果
/// </summary>
/// <param name="source">源字符串</param>
/// <returns>计算的结果</returns>
public static string ToHexString(string source)
public static string ToMd5HexString(string source)
{
byte[] hash = MD5.HashData(Encoding.UTF8.GetBytes(source));
return System.Convert.ToHexString(hash);

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.Win32;
using Snap.Hutao.Core.Convert;
using Snap.Hutao.Core.Json;
using Snap.Hutao.Extension;
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
@@ -31,7 +30,7 @@ internal static class CoreEnvironment
/// <summary>
/// 米游社 Rpc 版本
/// </summary>
public const string HoyolabXrpcVersion = "2.43.1";
public const string HoyolabXrpcVersion = "2.44.1";
/// <summary>
/// 盐
@@ -39,8 +38,8 @@ internal static class CoreEnvironment
// https://github.com/UIGF-org/Hoyolab.Salt
public static readonly ImmutableDictionary<string, string> DynamicSecrets = new Dictionary<string, string>()
{
[nameof(SaltType.K2)] = "ODzG1Jrn6zebX19VRmaJwjFI2CDvBUGq",
[nameof(SaltType.LK2)] = "V1PYbXKQY7ysdx3MNCcNbsE1LtY2QZpW",
[nameof(SaltType.K2)] = "dZAwGk4e9aC0MXXItkwnHamjA1x30IYw",
[nameof(SaltType.LK2)] = "IEIZiKYaput2OCKQprNuGsog1NZc1FkS",
[nameof(SaltType.X4)] = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
[nameof(SaltType.X6)] = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
[nameof(SaltType.PROD)] = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS",
@@ -113,7 +112,7 @@ internal static class CoreEnvironment
{
string userName = Environment.UserName;
object? machineGuid = Registry.GetValue(CryptographyKey, MachineGuidValue, userName);
return Md5Convert.ToHexString($"{userName}{machineGuid}");
return Convert.ToMd5HexString($"{userName}{machineGuid}");
}
private static string GetDocumentsHutaoPath()

View File

@@ -36,7 +36,7 @@ internal static class PickerExtension
{
Ioc.Default
.GetRequiredService<Service.Abstraction.IInfoBarService>()
.Warning($"无法打开文件选择器 {exception.Message}");
.Warning("无法打开文件选择器", $"请勿在管理员模式下使用此功能 {exception.Message}");
}
return new(false, null!);
@@ -68,7 +68,7 @@ internal static class PickerExtension
{
Ioc.Default
.GetRequiredService<Service.Abstraction.IInfoBarService>()
.Warning($"无法打开文件选择器 {exception.Message}");
.Warning("无法打开文件选择器", $"请勿在管理员模式下使用此功能 {exception.Message}");
}
return new(false, null!);

View File

@@ -11,8 +11,8 @@ internal class SeparatorCommaInt32EnumerableConverter : JsonConverter<IEnumerabl
/// <inheritdoc/>
public override IEnumerable<int> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? team = reader.GetString();
IEnumerable<int>? ids = team?.Split(',').Select(x => int.Parse(x));
string? source = reader.GetString();
IEnumerable<int>? ids = source?.Split(',').Select(int.Parse);
return ids ?? Enumerable.Empty<int>();
}

View File

@@ -10,6 +10,8 @@ namespace Snap.Hutao.Core.Json;
/// </summary>
internal class JsonTextEncoder : JavaScriptEncoder
{
private static readonly string BackSlashDoubleQuote = "\\\"";
/// <inheritdoc/>
public override int MaxOutputCharactersPerInputCharacter { get => 6; }
@@ -27,7 +29,7 @@ internal class JsonTextEncoder : JavaScriptEncoder
if (unicodeScalar == '"')
{
numberOfCharactersWritten = 2;
return "\\\"".AsSpan().TryCopyTo(new Span<char>(buffer, bufferLength));
return BackSlashDoubleQuote.AsSpan().TryCopyTo(new Span<char>(buffer, bufferLength));
}
string encoded = $"\\u{(uint)unicodeScalar:x4}";

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.Win32.TaskScheduler;
using System.IO;
using System.Runtime.InteropServices;
using SchedulerTask = Microsoft.Win32.TaskScheduler.Task;

View File

@@ -1,46 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Threading;
/// <summary>
/// Holds the task for a cancellation token, as well as the token registration. The registration is disposed when this instance is disposed.
/// </summary>
/// <typeparam name="T">包装类型</typeparam>
public sealed class CancellationTokenTaskCompletionSource : IDisposable
{
/// <summary>
/// The cancellation token registration, if any. This is <c>null</c> if the registration was not necessary.
/// </summary>
private readonly IDisposable? registration;
/// <summary>
/// Creates a task for the specified cancellation token, registering with the token if necessary.
/// </summary>
/// <param name="cancellationToken">The cancellation token to observe.</param>
public CancellationTokenTaskCompletionSource(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
Task = Task.CompletedTask;
return;
}
TaskCompletionSource tcs = new();
registration = cancellationToken.Register(() => tcs.TrySetResult(), useSynchronizationContext: false);
Task = tcs.Task;
}
/// <summary>
/// Gets the task for the source cancellation token.
/// </summary>
public Task Task { get; private set; }
/// <summary>
/// Disposes the cancellation token registration, if any. Note that this may cause <see cref="Task"/> to never complete.
/// </summary>
public void Dispose()
{
registration?.Dispose();
}
}

View File

@@ -17,15 +17,13 @@ public static class DispatcherQueueExtension
/// <param name="action">执行的回调</param>
public static void Invoke(this DispatcherQueue dispatcherQueue, Action action)
{
using (ManualResetEventSlim blockEvent = new())
ManualResetEventSlim blockEvent = new();
dispatcherQueue.TryEnqueue(() =>
{
dispatcherQueue.TryEnqueue(() =>
{
action();
blockEvent.Set();
});
action();
blockEvent.Set();
});
blockEvent.Wait();
}
blockEvent.Wait();
}
}

View File

@@ -11,7 +11,7 @@ public enum BackdropType
/// <summary>
/// 无
/// </summary>
None = 0,
None,
/// <summary>
/// 亚克力

View File

@@ -148,6 +148,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
IMessenger messenger = Ioc.Default.GetRequiredService<IMessenger>();
messenger.Register<BackdropTypeChangedMessage>(this);
messenger.Register<FlyoutOpenCloseMessage>(this);
window.Closed += OnWindowClosed;
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.IO;
namespace Snap.Hutao.Extension;
/// <summary>
/// <see cref="BinaryReader"/> 扩展
/// </summary>
public static class BinaryReaderExtension
{
/// <summary>
/// 判断是否处于流的结尾
/// </summary>
/// <param name="reader">读取器</param>
/// <returns>是否处于流的结尾</returns>
public static bool EndOfStream(this BinaryReader reader)
{
return reader.BaseStream.Position >= reader.BaseStream.Length;
}
}

View File

@@ -18,7 +18,7 @@ public static class DateTimeOffsetExtension
{
if (keepTicks)
{
dateTimeOffset += TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now).Negate();
dateTimeOffset -= TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);
}
return dateTimeOffset.ToLocalTime();

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Snap.Hutao.Extension;
@@ -37,6 +38,7 @@ public static partial class EnumerableExtension
/// <typeparam name="TSource">源类型</typeparam>
/// <param name="source">源</param>
/// <returns>源列表或空列表</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static List<TSource> EmptyIfNull<TSource>(this List<TSource>? source)
{
return source ?? new();

View File

@@ -9,13 +9,6 @@ namespace Snap.Hutao.Extension;
[SuppressMessage("", "CA2254")]
public static class LoggerExtension
{
/// <inheritdoc cref="LoggerExtensions.LogInformation(ILogger, string?, object?[])"/>
public static T LogInformation<T>(this ILogger logger, string message, params object?[] param)
{
logger.LogInformation(message, param);
return default!;
}
/// <inheritdoc cref="LoggerExtensions.LogWarning(ILogger, string?, object?[])"/>
public static T LogWarning<T>(this ILogger logger, string message, params object?[] param)
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Extension;
/// <summary>
@@ -8,36 +10,15 @@ namespace Snap.Hutao.Extension;
/// </summary>
public static class NumberExtension
{
/// <summary>
/// 获取从右向左某位上的数字
/// </summary>
/// <param name="x">源</param>
/// <param name="place">位</param>
/// <returns>数字</returns>
public static int AtPlace(this int x, int place)
{
return (int)(x / Math.Pow(10, place - 1)) % 10;
}
/// <summary>
/// 计算给定整数的位数
/// </summary>
/// <param name="x">给定的整数</param>
/// <returns>位数</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Place(this int x)
{
// Benchmarked and compared as a most optimized solution
return (int)(MathF.Log10(x) + 1);
}
/// <summary>
/// 计算给定整数的位数
/// </summary>
/// <param name="x">给定的整数</param>
/// <returns>位数</returns>
public static int Place(this long x)
{
// Benchmarked and compared as a most optimized solution
return (int)(MathF.Log10(x) + 1);
}
}

View File

@@ -1,76 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
namespace Snap.Hutao.Factory.Abstraction;
/// <summary>
/// Factory for creating <see cref="AsyncRelayCommand"/> with additional processing.
/// </summary>
public interface IAsyncRelayCommandFactory
{
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute, Func<bool> canExecute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand Create(Func<Task> execute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand Create(Func<Task> execute, Func<bool> canExecute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <typeparam name="T">The type of the command parameter.</typeparam>
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <typeparam name="T">The type of the command parameter.</typeparam>
/// <param name="cancelableExecute">The cancelable execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute, Predicate<T?> canExecute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <typeparam name="T">The type of the command parameter.</typeparam>
/// <param name="execute">The execution logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute);
/// <summary>
/// Create a reference to AsyncRelayCommand.
/// </summary>
/// <typeparam name="T">The type of the command parameter.</typeparam>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
/// <returns>AsyncRelayCommand.</returns>
AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute, Predicate<T?> canExecute);
}

View File

@@ -1,102 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Factory.Abstraction;
namespace Snap.Hutao.Factory;
/// <inheritdoc cref="IAsyncRelayCommandFactory"/>
[Injection(InjectAs.Transient, typeof(IAsyncRelayCommandFactory))]
internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory
{
private readonly ILogger<AsyncRelayCommandFactory> logger;
/// <summary>
/// 构造一个新的异步命令工厂
/// </summary>
/// <param name="logger">日志器</param>
public AsyncRelayCommandFactory(ILogger<AsyncRelayCommandFactory> logger)
{
this.logger = logger;
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute)
{
return Register(new AsyncRelayCommand<T>(execute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute)
{
return Register(new AsyncRelayCommand<T>(cancelableExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute, Predicate<T?> canExecute)
{
return Register(new AsyncRelayCommand<T>(execute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute, Predicate<T?> canExecute)
{
return Register(new AsyncRelayCommand<T>(cancelableExecute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<Task> execute)
{
return Register(new AsyncRelayCommand(execute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute)
{
return Register(new AsyncRelayCommand(cancelableExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<Task> execute, Func<bool> canExecute)
{
return Register(new AsyncRelayCommand(execute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute, Func<bool> canExecute)
{
return Register(new AsyncRelayCommand(cancelableExecute, canExecute));
}
private AsyncRelayCommand Register(AsyncRelayCommand command)
{
ReportException(command);
return command;
}
private AsyncRelayCommand<T> Register<T>(AsyncRelayCommand<T> command)
{
ReportException(command);
return command;
}
private void ReportException(IAsyncRelayCommand command)
{
command.PropertyChanged += (sender, args) =>
{
if (sender is IAsyncRelayCommand asyncRelayCommand)
{
if (args.PropertyName == nameof(AsyncRelayCommand.ExecutionTask))
{
if (asyncRelayCommand.ExecutionTask?.Exception is AggregateException exception)
{
Exception baseException = exception.GetBaseException();
logger.LogError(EventIds.AsyncCommandException, baseException, "{name} Exception", nameof(AsyncRelayCommand));
}
}
}
};
}
}

View File

@@ -31,10 +31,10 @@ public class Costume
/// <summary>
/// 图标
/// </summary>
public string? Icon { get; set; }
public string Icon { get; set; } = default!;
/// <summary>
/// 侧面图标
/// </summary>
public string? SideIcon { get; set; }
public string SideIcon { get; set; } = default!;
}

View File

@@ -97,8 +97,18 @@ public static class AvatarIds
{
return new(idAvatarMap)
{
[PlayerBoy] = new() { Name = "旅行者", Icon = "UI_AvatarIcon_PlayerBoy", Quality = Intrinsic.ItemQuality.QUALITY_ORANGE },
[PlayerGirl] = new() { Name = "旅行者", Icon = "UI_AvatarIcon_PlayerGirl", Quality = Intrinsic.ItemQuality.QUALITY_ORANGE },
[PlayerBoy] = new()
{
Name = "旅行者",
Icon = "UI_AvatarIcon_PlayerBoy",
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
},
[PlayerGirl] = new()
{
Name = "旅行者",
Icon = "UI_AvatarIcon_PlayerGirl",
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
},
};
}
}

View File

@@ -34,6 +34,8 @@ internal class ElementNameIconConverter : ValueConverter<string, Uri>
return string.IsNullOrEmpty(element)
? Web.HutaoEndpoints.UIIconNone
: new Uri(Web.HutaoEndpoints.StaticFile("IconElement", $"UI_Icon_Element_{element}.png"));
// $"UI_Icon_Element_{element}.png"
}
/// <summary>

View File

@@ -6,7 +6,7 @@ using Snap.Hutao.Model.Metadata;
namespace Snap.Hutao.Service.AvatarInfo.Factory;
/// <summary>
/// 权重配置
/// 圣遗物评分权重配置
/// </summary>
internal static partial class ReliquaryWeightConfiguration
{

View File

@@ -45,28 +45,53 @@ internal class SummaryAvatarFactory
PropertyAvatar propertyAvatar = new()
{
// metadata part
Id = avatar.Id,
Name = avatar.Name,
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon),
SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon),
NameCard = AvatarNameCardPicConverter.AvatarToUri(avatar),
Quality = avatar.Quality,
Element = ElementNameIconConverter.ElementNameToElementType(avatar.FetterInfo.VisionBefore),
FetterLevel = avatarInfo.FetterInfo.ExpLevel,
Weapon = reliquaryAndWeapon.Weapon,
Reliquaries = reliquaryAndWeapon.Reliquaries,
// webinfo & metadata mixed part
Constellations = SummaryHelper.CreateConstellations(avatarInfo.TalentIdList, avatar.SkillDepot.Talents),
Skills = SummaryHelper.CreateSkills(avatarInfo.SkillLevelMap, avatarInfo.ProudSkillExtraLevelMap, avatar.SkillDepot.GetCompositeSkillsNoInherents()),
// webinfo part
FetterLevel = avatarInfo.FetterInfo?.ExpLevel ?? 0,
Properties = SummaryHelper.CreateAvatarProperties(avatarInfo.FightPropMap),
Score = reliquaryAndWeapon.Reliquaries.Sum(r => r.Score).ToString("F2"),
CritScore = $"{SummaryHelper.ScoreCrit(avatarInfo.FightPropMap):F2}",
LevelNumber = int.Parse(avatarInfo.PropMap?[PlayerProperty.PROP_LEVEL].Value ?? string.Empty),
// processed webinfo part
Weapon = reliquaryAndWeapon.Weapon,
Reliquaries = reliquaryAndWeapon.Reliquaries,
Score = reliquaryAndWeapon.Reliquaries.Sum(r => r.Score).ToString("F2"),
};
TryApplyCostumeIconToAvatar(ref propertyAvatar, avatar);
propertyAvatar.Level = $"Lv.{propertyAvatar.LevelNumber}";
return propertyAvatar;
}
private void TryApplyCostumeIconToAvatar(ref PropertyAvatar propertyAvatar, MetadataAvatar avatar)
{
// Set to costume icon
if (avatarInfo.CostumeId.HasValue)
{
int costumeId = avatarInfo.CostumeId.Value;
Model.Metadata.Avatar.Costume costume = avatar.Costumes.Single(c => c.Id == costumeId);
propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(costume.Icon);
propertyAvatar.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon);
}
else
{
propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
propertyAvatar.SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon);
}
}
private ReliquaryAndWeapon ProcessEquip(List<Equip> equipments)
{
List<PropertyReliquary> reliquaryList = new();

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Win32.SafeHandles;
using Snap.Hutao.Core.Diagnostics;
using Snap.Hutao.Win32;
using System.Diagnostics;

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Core.Abstraction;
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Core.Diagnostics;
using Snap.Hutao.Core.Logging;
@@ -20,7 +19,7 @@ namespace Snap.Hutao.Service.Metadata;
/// </summary>
[Injection(InjectAs.Singleton, typeof(IMetadataService))]
[HttpClient(HttpClientConfigration.Default)]
internal partial class MetadataService : IMetadataService, IMetadataInitializer, ISupportAsyncInitialization
internal partial class MetadataService : IMetadataService, IMetadataInitializer
{
private const string MetaFileName = "Meta.json";
@@ -63,14 +62,11 @@ internal partial class MetadataService : IMetadataService, IMetadataInitializer,
Directory.CreateDirectory(metadataFolderPath);
}
/// <inheritdoc/>
public bool IsInitialized { get => isInitialized; private set => isInitialized = value; }
/// <inheritdoc/>
public async ValueTask<bool> InitializeAsync()
{
await initializeCompletionSource.Task.ConfigureAwait(false);
return IsInitialized;
return isInitialized;
}
/// <inheritdoc/>
@@ -79,7 +75,7 @@ internal partial class MetadataService : IMetadataService, IMetadataInitializer,
ValueStopwatch stopwatch = ValueStopwatch.StartNew();
logger.LogInformation(EventIds.MetadataInitialization, "Metadata initializaion begin");
IsInitialized = await TryUpdateMetadataAsync(token).ConfigureAwait(false);
isInitialized = await TryUpdateMetadataAsync(token).ConfigureAwait(false);
initializeCompletionSource.SetResult();
logger.LogInformation(EventIds.MetadataInitialization, "Metadata initializaion completed in {time}ms", stopwatch.GetElapsedTime().TotalMilliseconds);
@@ -186,7 +182,7 @@ internal partial class MetadataService : IMetadataService, IMetadataInitializer,
private async ValueTask<T> FromCacheOrFileAsync<T>(string fileName, CancellationToken token)
where T : class
{
Verify.Operation(IsInitialized, "元数据服务尚未初始化,或初始化失败");
Verify.Operation(isInitialized, "元数据服务尚未初始化,或初始化失败");
string cacheKey = $"{nameof(MetadataService)}.Cache.{fileName}";
if (memoryCache.TryGetValue(cacheKey, out object? value))
@@ -204,7 +200,6 @@ internal partial class MetadataService : IMetadataService, IMetadataInitializer,
private async ValueTask<Dictionary<TKey, TValue>> FromCacheAsDictionaryAsync<TKey, TValue>(string fileName, Func<TValue, TKey> keySelector, CancellationToken token)
where TKey : notnull
{
Verify.Operation(IsInitialized, "元数据服务尚未初始化,或初始化失败");
string cacheKey = $"{nameof(MetadataService)}.Cache.{fileName}.Map.{typeof(TKey).Name}";
if (memoryCache.TryGetValue(cacheKey, out object? value))
@@ -218,9 +213,8 @@ internal partial class MetadataService : IMetadataService, IMetadataInitializer,
}
private async ValueTask<Dictionary<TKey, TValue>> FromCacheAsDictionaryAsync<TKey, TValue, TData>(string fileName, Func<TData, TKey> keySelector, Func<TData, TValue> valueSelector, CancellationToken token)
where TKey : notnull
where TKey : notnull
{
Verify.Operation(IsInitialized, "元数据服务尚未初始化,或初始化失败");
string cacheKey = $"{nameof(MetadataService)}.Cache.{fileName}.Map.{typeof(TKey).Name}.{typeof(TValue).Name}";
if (memoryCache.TryGetValue(cacheKey, out object? value))

View File

@@ -97,8 +97,15 @@ internal class UserService : IUserService
await ThreadHelper.SwitchToBackgroundAsync();
using (IServiceScope scope = scopeFactory.CreateScope())
{
// Note: cascade deleted dailynotes
await scope.ServiceProvider.GetRequiredService<AppDbContext>().Users.RemoveAndSaveAsync(user.Entity).ConfigureAwait(false);
try
{
// Note: cascade deleted dailynotes
await scope.ServiceProvider.GetRequiredService<AppDbContext>().Users.RemoveAndSaveAsync(user.Entity).ConfigureAwait(false);
}
catch (DbUpdateConcurrencyException ex)
{
throw new Core.ExceptionService.UserdataCorruptedException("用户已被其他功能删除", ex);
}
}
messenger.Send(new UserRemovedMessage(user.Entity));

View File

@@ -154,7 +154,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
@@ -182,7 +182,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="WinUICommunity.SettingsUI" Version="3.0.1" />
<PackageReference Include="WinUICommunity.SettingsUI" Version="3.0.2" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>

View File

@@ -6,8 +6,6 @@ using Microsoft.UI.Xaml.Navigation;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Extension;
using System.Diagnostics;
using Windows.System;
namespace Snap.Hutao.View.Page;
@@ -69,7 +67,8 @@ public sealed partial class AnnouncementContentPage : Microsoft.UI.Xaml.Controls
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
//WebView.CoreWebView2.Environment.Exit();
// WebView.CoreWebView2.Environment.Exit();
}
private static string? ReplaceForeground(string? rawContent, ElementTheme theme)

View File

@@ -9,6 +9,7 @@
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shcp="using:Snap.Hutao.Control.Panel"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:wsc="using:WinUICommunity.SettingsUI.Controls"
@@ -219,16 +220,18 @@
</ListView>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
<StackPanel Margin="16,0,16,0">
<Border
MaxWidth="690"
MaxHeight="320"
Margin="0,16,0,0"
HorizontalAlignment="Left"
BorderBrush="{StaticResource CardStrokeColorDefault}"
BorderThickness="1"
CornerRadius="{StaticResource CompatCornerRadius}">
<shci:CachedImage MaxHeight="320" Source="{Binding SelectedHistoryWish.BannerImage}"/>
Style="{StaticResource BorderCardStyle}">
<Grid>
<shcp:AspectRatio TargetHeight="320" TargetWidth="690"/>
<shci:CachedImage Source="{Binding SelectedHistoryWish.BannerImage}"/>
</Grid>
</Border>
<TextBlock

View File

@@ -57,7 +57,6 @@ internal class AchievementViewModel : Abstraction.ViewModel, INavigationRecipien
/// <param name="achievementService">成就服务</param>
/// <param name="infoBarService">信息条服务</param>
/// <param name="options">Json序列化选项</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="contentDialogFactory">内容对话框工厂</param>
/// <param name="messenger">消息器</param>
public AchievementViewModel(
@@ -65,7 +64,6 @@ internal class AchievementViewModel : Abstraction.ViewModel, INavigationRecipien
IAchievementService achievementService,
IInfoBarService infoBarService,
JsonSerializerOptions options,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
IContentDialogFactory contentDialogFactory,
IMessenger messenger)
{
@@ -75,12 +73,12 @@ internal class AchievementViewModel : Abstraction.ViewModel, INavigationRecipien
this.contentDialogFactory = contentDialogFactory;
this.options = options;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
ImportUIAFFromClipboardCommand = asyncRelayCommandFactory.Create(ImportUIAFFromClipboardAsync);
ImportUIAFFromFileCommand = asyncRelayCommandFactory.Create(ImportUIAFFromFileAsync);
ExportAsUIAFToFileCommand = asyncRelayCommandFactory.Create(ExportAsUIAFToFileAsync);
AddArchiveCommand = asyncRelayCommandFactory.Create(AddArchiveAsync);
RemoveArchiveCommand = asyncRelayCommandFactory.Create(RemoveArchiveAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
ImportUIAFFromClipboardCommand = new AsyncRelayCommand(ImportUIAFFromClipboardAsync);
ImportUIAFFromFileCommand = new AsyncRelayCommand(ImportUIAFFromFileAsync);
ExportAsUIAFToFileCommand = new AsyncRelayCommand(ExportAsUIAFToFileAsync);
AddArchiveCommand = new AsyncRelayCommand(AddArchiveAsync);
RemoveArchiveCommand = new AsyncRelayCommand(RemoveArchiveAsync);
SearchAchievementCommand = new RelayCommand<string>(SearchAchievement);
SortIncompletedSwitchCommand = new RelayCommand(UpdateAchievementsSort);
SaveAchievementCommand = new RelayCommand<Model.Binding.Achievement.Achievement>(SaveAchievement);

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Page;
@@ -25,15 +24,11 @@ internal class AnnouncementViewModel : Abstraction.ViewModel
/// 构造一个公告视图模型
/// </summary>
/// <param name="announcementService">公告服务</param>
/// <param name="navigationService">导航服务</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="infoBarService">信息条服务</param>
/// <param name="logger">日志器</param>
public AnnouncementViewModel(IAnnouncementService announcementService, IAsyncRelayCommandFactory asyncRelayCommandFactory)
public AnnouncementViewModel(IAnnouncementService announcementService)
{
this.announcementService = announcementService;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
OpenAnnouncementUICommand = new RelayCommand<string>(OpenAnnouncementUI);
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
@@ -51,13 +52,11 @@ internal class AvatarPropertyViewModel : Abstraction.ViewModel
/// <param name="userService">用户服务</param>
/// <param name="avatarInfoService">角色信息服务</param>
/// <param name="contentDialogFactory">对话框工厂</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="infoBarService">信息条服务</param>
public AvatarPropertyViewModel(
IUserService userService,
IAvatarInfoService avatarInfoService,
IContentDialogFactory contentDialogFactory,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
IInfoBarService infoBarService)
{
this.userService = userService;
@@ -65,12 +64,12 @@ internal class AvatarPropertyViewModel : Abstraction.ViewModel
this.infoBarService = infoBarService;
this.contentDialogFactory = contentDialogFactory;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
RefreshFromEnkaApiCommand = asyncRelayCommandFactory.Create(RefreshByEnkaApiAsync);
RefreshFromHoyolabGameRecordCommand = asyncRelayCommandFactory.Create(RefreshByHoyolabGameRecordAsync);
RefreshFromHoyolabCalculateCommand = asyncRelayCommandFactory.Create(RefreshByHoyolabCalculateAsync);
ExportAsImageCommand = asyncRelayCommandFactory.Create<UIElement>(ExportAsImageAsync);
CultivateCommand = asyncRelayCommandFactory.Create<Avatar>(CultivateAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
RefreshFromEnkaApiCommand = new AsyncRelayCommand(RefreshByEnkaApiAsync);
RefreshFromHoyolabGameRecordCommand = new AsyncRelayCommand(RefreshByHoyolabGameRecordAsync);
RefreshFromHoyolabCalculateCommand = new AsyncRelayCommand(RefreshByHoyolabCalculateAsync);
ExportAsImageCommand = new AsyncRelayCommand<UIElement>(ExportAsImageAsync);
CultivateCommand = new AsyncRelayCommand<Avatar>(CultivateAsync);
}
/// <summary>

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding.Cultivation;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Abstraction;
@@ -36,13 +35,11 @@ internal class CultivationViewModel : Abstraction.ViewModel
/// </summary>
/// <param name="cultivationService">养成服务</param>
/// <param name="infoBarService">信息服务</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="metadataService">元数据服务</param>
/// <param name="logger">日志器</param>
public CultivationViewModel(
ICultivationService cultivationService,
IInfoBarService infoBarService,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
IMetadataService metadataService,
ILogger<CultivationViewModel> logger)
{
@@ -51,12 +48,12 @@ internal class CultivationViewModel : Abstraction.ViewModel
this.metadataService = metadataService;
this.logger = logger;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
AddProjectCommand = asyncRelayCommandFactory.Create(AddProjectAsync);
RemoveProjectCommand = asyncRelayCommandFactory.Create<CultivateProject>(RemoveProjectAsync);
RemoveEntryCommand = asyncRelayCommandFactory.Create<Model.Binding.Cultivation.CultivateEntry>(RemoveEntryAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
AddProjectCommand = new AsyncRelayCommand(AddProjectAsync);
RemoveProjectCommand = new AsyncRelayCommand<CultivateProject>(RemoveProjectAsync);
RemoveEntryCommand = new AsyncRelayCommand<Model.Binding.Cultivation.CultivateEntry>(RemoveEntryAsync);
SaveInventoryItemCommand = new RelayCommand<Model.Binding.Inventory.InventoryItem>(SaveInventoryItem);
UpdateStatisticsItemsCommand = asyncRelayCommandFactory.Create(UpdateStatisticsItemsAsync);
UpdateStatisticsItemsCommand = new AsyncRelayCommand(UpdateStatisticsItemsAsync);
NavigateToPageCommand = new RelayCommand<string>(NavigateToPage);
}

View File

@@ -4,7 +4,6 @@
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model;
using Snap.Hutao.Model.Binding.User;
using Snap.Hutao.Model.Entity;
@@ -52,23 +51,21 @@ internal class DailyNoteViewModel : Abstraction.ViewModel
/// <param name="userService">用户服务</param>
/// <param name="dailyNoteService">实时便笺服务</param>
/// <param name="appDbContext">数据库上下文</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public DailyNoteViewModel(
IUserService userService,
IDailyNoteService dailyNoteService,
AppDbContext appDbContext,
IAsyncRelayCommandFactory asyncRelayCommandFactory)
AppDbContext appDbContext)
{
this.userService = userService;
this.dailyNoteService = dailyNoteService;
this.appDbContext = appDbContext;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
TrackRoleCommand = asyncRelayCommandFactory.Create<UserAndUid>(TrackRoleAsync);
RefreshCommand = asyncRelayCommandFactory.Create(RefreshAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
TrackRoleCommand = new AsyncRelayCommand<UserAndUid>(TrackRoleAsync);
RefreshCommand = new AsyncRelayCommand(RefreshAsync);
RemoveDailyNoteCommand = new RelayCommand<DailyNoteEntry>(RemoveDailyNote);
ModifyNotificationCommand = asyncRelayCommandFactory.Create<DailyNoteEntry>(ModifyDailyNoteNotificationAsync);
DailyNoteVerificationCommand = asyncRelayCommandFactory.Create(VerifyDailyNoteVerificationAsync);
ModifyNotificationCommand = new AsyncRelayCommand<DailyNoteEntry>(ModifyDailyNoteNotificationAsync);
DailyNoteVerificationCommand = new AsyncRelayCommand(VerifyDailyNoteVerificationAsync);
}
/// <summary>
@@ -176,7 +173,16 @@ internal class DailyNoteViewModel : Abstraction.ViewModel
private async Task OpenUIAsync()
{
UserAndUids = await userService.GetRoleCollectionAsync().ConfigureAwait(false);
try
{
UserAndUids = await userService.GetRoleCollectionAsync().ConfigureAwait(false);
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
Ioc.Default.GetRequiredService<IInfoBarService>().Error(ex);
return;
}
try
{
ThrowIfViewDisposed();

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Entity.Database;
using Snap.Hutao.Service.Abstraction;
using Windows.Storage;
@@ -22,12 +21,11 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
/// <summary>
/// 构造一个新的实验性功能视图模型
/// </summary>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public ExperimentalFeaturesViewModel(IAsyncRelayCommandFactory asyncRelayCommandFactory)
public ExperimentalFeaturesViewModel()
{
OpenCacheFolderCommand = asyncRelayCommandFactory.Create(OpenCacheFolderAsync);
OpenDataFolderCommand = asyncRelayCommandFactory.Create(OpenDataFolderAsync);
DeleteUsersCommand = asyncRelayCommandFactory.Create(DangerousDeleteUsersAsync);
OpenCacheFolderCommand = new AsyncRelayCommand(OpenCacheFolderAsync);
OpenDataFolderCommand = new AsyncRelayCommand(OpenDataFolderAsync);
DeleteUsersCommand = new AsyncRelayCommand(DangerousDeleteUsersAsync);
DeleteAllScheduleTasksCommand = new RelayCommand(DangerousDeleteAllScheduleTasks);
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Data.Sqlite;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Core.IO;
@@ -41,14 +41,12 @@ internal class GachaLogViewModel : Abstraction.ViewModel
/// <param name="gachaLogService">祈愿记录服务</param>
/// <param name="infoBarService">信息</param>
/// <param name="options">Json序列化选项</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="contentDialogFactory">内容对话框工厂</param>
/// <param name="pickerFactory">文件选择器工厂</param>
public GachaLogViewModel(
IGachaLogService gachaLogService,
IInfoBarService infoBarService,
JsonSerializerOptions options,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
IContentDialogFactory contentDialogFactory,
IPickerFactory pickerFactory)
{
@@ -58,13 +56,13 @@ internal class GachaLogViewModel : Abstraction.ViewModel
this.contentDialogFactory = contentDialogFactory;
this.options = options;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
RefreshByWebCacheCommand = asyncRelayCommandFactory.Create(RefreshByWebCacheAsync);
RefreshByStokenCommand = asyncRelayCommandFactory.Create(RefreshByStokenAsync);
RefreshByManualInputCommand = asyncRelayCommandFactory.Create(RefreshByManualInputAsync);
ImportFromUIGFJsonCommand = asyncRelayCommandFactory.Create(ImportFromUIGFJsonAsync);
ExportToUIGFJsonCommand = asyncRelayCommandFactory.Create(ExportToUIGFJsonAsync);
RemoveArchiveCommand = asyncRelayCommandFactory.Create(RemoveArchiveAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
RefreshByWebCacheCommand = new AsyncRelayCommand(RefreshByWebCacheAsync);
RefreshByStokenCommand = new AsyncRelayCommand(RefreshByStokenAsync);
RefreshByManualInputCommand = new AsyncRelayCommand(RefreshByManualInputAsync);
ImportFromUIGFJsonCommand = new AsyncRelayCommand(ImportFromUIGFJsonAsync);
ExportToUIGFJsonCommand = new AsyncRelayCommand(ExportToUIGFJsonAsync);
RemoveArchiveCommand = new AsyncRelayCommand(RemoveArchiveAsync);
}
/// <summary>
@@ -202,24 +200,27 @@ internal class GachaLogViewModel : Abstraction.ViewModel
Progress<FetchState> progress = new(dialog.OnReport);
bool authkeyValid;
using (await DisposeLock.EnterAsync().ConfigureAwait(false))
try
{
try
using (await DisposeLock.EnterAsync().ConfigureAwait(false))
{
authkeyValid = await gachaLogService.RefreshGachaLogAsync(query, strategy, progress, CancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// We set true here in order to hide the dialog.
authkeyValid = true;
infoBarService.Warning("祈愿记录刷新操作被异常取消");
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
authkeyValid = false;
infoBarService.Error(ex);
try
{
authkeyValid = await gachaLogService.RefreshGachaLogAsync(query, strategy, progress, CancellationToken).ConfigureAwait(false);
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
authkeyValid = false;
infoBarService.Error(ex);
}
}
}
catch (OperationCanceledException)
{
// We set true here in order to hide the dialog.
authkeyValid = true;
infoBarService.Warning("祈愿记录刷新操作被异常取消");
}
await ThreadHelper.SwitchToMainThreadAsync();
if (authkeyValid)

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Factory.Abstraction;
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Web.Hutao.Model;
@@ -26,12 +26,11 @@ internal class HutaoDatabaseViewModel : Abstraction.ViewModel
/// 构造一个新的胡桃数据库视图模型
/// </summary>
/// <param name="hutaoCache">胡桃服务缓存</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public HutaoDatabaseViewModel(IHutaoCache hutaoCache, IAsyncRelayCommandFactory asyncRelayCommandFactory)
public HutaoDatabaseViewModel(IHutaoCache hutaoCache)
{
this.hutaoCache = hutaoCache;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
/// <summary>

View File

@@ -6,7 +6,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding.LaunchGame;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
@@ -62,22 +61,20 @@ internal class LaunchGameViewModel : Abstraction.ViewModel
/// <param name="gameService">游戏服务</param>
/// <param name="memoryCache">内存缓存</param>
/// <param name="appDbContext">数据库上下文</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public LaunchGameViewModel(
IGameService gameService,
IMemoryCache memoryCache,
AppDbContext appDbContext,
IAsyncRelayCommandFactory asyncRelayCommandFactory)
AppDbContext appDbContext)
{
this.gameService = gameService;
this.appDbContext = appDbContext;
this.memoryCache = memoryCache;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
LaunchCommand = asyncRelayCommandFactory.Create(LaunchAsync);
DetectGameAccountCommand = asyncRelayCommandFactory.Create(DetectGameAccountAsync);
ModifyGameAccountCommand = asyncRelayCommandFactory.Create<GameAccount>(ModifyGameAccountAsync);
RemoveGameAccountCommand = asyncRelayCommandFactory.Create<GameAccount>(RemoveGameAccountAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
LaunchCommand = new AsyncRelayCommand(LaunchAsync);
DetectGameAccountCommand = new AsyncRelayCommand(DetectGameAccountAsync);
ModifyGameAccountCommand = new AsyncRelayCommand<GameAccount>(ModifyGameAccountAsync);
RemoveGameAccountCommand = new AsyncRelayCommand<GameAccount>(RemoveGameAccountAsync);
AttachGameAccountCommand = new RelayCommand<GameAccount>(AttachGameAccountToCurrentUserGameRole);
}

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
@@ -45,13 +44,11 @@ internal class SettingViewModel : Abstraction.ViewModel
/// </summary>
/// <param name="appDbContext">数据库上下文</param>
/// <param name="gameService">游戏服务</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="experimental">实验性功能</param>
/// <param name="logger">日志器</param>
public SettingViewModel(
AppDbContext appDbContext,
IGameService gameService,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
ExperimentalFeaturesViewModel experimental,
ILogger<SettingViewModel> logger)
{
@@ -73,10 +70,10 @@ internal class SettingViewModel : Abstraction.ViewModel
GamePath = gameService.GetGamePathSkipLocator();
SetGamePathCommand = asyncRelayCommandFactory.Create(SetGamePathAsync);
DebugExceptionCommand = asyncRelayCommandFactory.Create(DebugThrowExceptionAsync);
SetGamePathCommand = new AsyncRelayCommand(SetGamePathAsync);
DebugExceptionCommand = new AsyncRelayCommand(DebugThrowExceptionAsync);
DeleteGameWebCacheCommand = new RelayCommand(DeleteGameWebCache);
ShowSignInWebViewDialogCommand = asyncRelayCommandFactory.Create(ShowSignInWebViewDialogAsync);
ShowSignInWebViewDialogCommand = new AsyncRelayCommand(ShowSignInWebViewDialogAsync);
}
/// <summary>

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Message;
using Snap.Hutao.Model.Binding.SpiralAbyss;
using Snap.Hutao.Model.Binding.User;
@@ -40,22 +40,20 @@ internal class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecipient<Us
/// <param name="spiralAbyssRecordService">深渊记录服务</param>
/// <param name="metadataService">元数据服务</param>
/// <param name="userService">用户服务</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="messenger">消息器</param>
public SpiralAbyssRecordViewModel(
ISpiralAbyssRecordService spiralAbyssRecordService,
IMetadataService metadataService,
IUserService userService,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
IMessenger messenger)
{
this.spiralAbyssRecordService = spiralAbyssRecordService;
this.metadataService = metadataService;
this.userService = userService;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
RefreshCommand = asyncRelayCommandFactory.Create(RefreshAsync);
UploadSpiralAbyssRecordCommand = asyncRelayCommandFactory.Create(UploadSpiralAbyssRecordAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
RefreshCommand = new AsyncRelayCommand(RefreshAsync);
UploadSpiralAbyssRecordCommand = new AsyncRelayCommand(UploadSpiralAbyssRecordAsync);
messenger.Register(this);
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.IO.Bits;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Hoyolab;
@@ -22,13 +21,12 @@ internal class TestViewModel : Abstraction.ViewModel
/// <summary>
/// 构造一个新的测试视图模型
/// </summary>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public TestViewModel(IAsyncRelayCommandFactory asyncRelayCommandFactory)
public TestViewModel()
{
ShowCommunityGameRecordDialogCommand = asyncRelayCommandFactory.Create(ShowCommunityGameRecordDialogAsync);
ShowAdoptCalculatorDialogCommand = asyncRelayCommandFactory.Create(ShowAdoptCalculatorDialogAsync);
DangerousLoginMihoyoBbsCommand = asyncRelayCommandFactory.Create(DangerousLoginMihoyoBbsAsync);
DownloadStaticFileCommand = asyncRelayCommandFactory.Create(DownloadStaticFileAsync);
ShowCommunityGameRecordDialogCommand = new AsyncRelayCommand(ShowCommunityGameRecordDialogAsync);
ShowAdoptCalculatorDialogCommand = new AsyncRelayCommand(ShowAdoptCalculatorDialogAsync);
DangerousLoginMihoyoBbsCommand = new AsyncRelayCommand(DangerousLoginMihoyoBbsAsync);
DownloadStaticFileCommand = new AsyncRelayCommand(DownloadStaticFileAsync);
}
/// <summary>

View File

@@ -3,10 +3,9 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Data.Sqlite;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO.DataTransfer;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding.User;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Navigation;
@@ -36,16 +35,15 @@ internal class UserViewModel : ObservableObject
/// </summary>
/// <param name="userService">用户服务</param>
/// <param name="infoBarService">信息条服务</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public UserViewModel(IUserService userService, IInfoBarService infoBarService, IAsyncRelayCommandFactory asyncRelayCommandFactory)
public UserViewModel(IUserService userService, IInfoBarService infoBarService)
{
this.userService = userService;
this.infoBarService = infoBarService;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
AddUserCommand = asyncRelayCommandFactory.Create(AddUserAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
AddUserCommand = new AsyncRelayCommand(AddUserAsync);
LoginMihoyoUserCommand = new RelayCommand(LoginMihoyoUser);
RemoveUserCommand = asyncRelayCommandFactory.Create<User>(RemoveUserAsync);
RemoveUserCommand = new AsyncRelayCommand<User>(RemoveUserAsync);
CopyCookieCommand = new RelayCommand<User>(CopyCookie);
}
@@ -106,10 +104,9 @@ internal class UserViewModel : ObservableObject
Users = await userService.GetUserCollectionAsync().ConfigureAwait(true);
SelectedUser = userService.Current;
}
catch (SqliteException ex)
catch (UserdataCorruptedException ex)
{
// SQLite Error 11: 'database disk image is malformed'.
infoBarService.Error(ex, "用户数据文件已损坏");
infoBarService.Error(ex);
}
}
@@ -168,9 +165,18 @@ internal class UserViewModel : ObservableObject
private async Task RemoveUserAsync(User? user)
{
Verify.Operation(user != null, "待删除的用户不应为 null");
await userService.RemoveUserAsync(user).ConfigureAwait(false);
infoBarService.Success($"用户 [{user.UserInfo?.Nickname}] 成功移除");
if (user != null)
{
try
{
await userService.RemoveUserAsync(user!).ConfigureAwait(false);
infoBarService.Success($"用户 [{user.UserInfo?.Nickname}] 成功移除");
}
catch (UserdataCorruptedException ex)
{
infoBarService.Error(ex);
}
}
}
private void CopyCookie(User? user)

View File

@@ -3,6 +3,7 @@
using CommunityToolkit.Common;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.WinUI.Notifications;
using Microsoft.Extensions.DependencyInjection;
@@ -11,7 +12,6 @@ using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.IO.Bits;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Compression;
@@ -32,12 +32,11 @@ internal class WelcomeViewModel : ObservableObject
/// <summary>
/// 构造一个新的欢迎视图模型
/// </summary>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
/// <param name="serviceProvider">服务提供器</param>
public WelcomeViewModel(IAsyncRelayCommandFactory asyncRelayCommandFactory, IServiceProvider serviceProvider)
public WelcomeViewModel(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
/// <summary>

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.UI;
using Microsoft.Extensions.Primitives;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding.Cultivation;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Intrinsic;
@@ -46,13 +45,12 @@ internal class WikiAvatarViewModel : Abstraction.ViewModel
/// </summary>
/// <param name="metadataService">元数据服务</param>
/// <param name="hutaoCache">胡桃缓存</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public WikiAvatarViewModel(IMetadataService metadataService, IHutaoCache hutaoCache, IAsyncRelayCommandFactory asyncRelayCommandFactory)
public WikiAvatarViewModel(IMetadataService metadataService, IHutaoCache hutaoCache)
{
this.metadataService = metadataService;
this.hutaoCache = hutaoCache;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
CultivateCommand = asyncRelayCommandFactory.Create<Avatar>(CultivateAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand<Avatar>(CultivateAsync);
FilterCommand = new RelayCommand<string>(ApplyFilter);
}
@@ -199,7 +197,7 @@ internal class WikiAvatarViewModel : Abstraction.ViewModel
private static bool DoFilter(string input, Avatar avatar)
{
bool keep = false;
bool keep = true;
foreach (StringSegment segment in new StringTokenizer(input, ' '.Enumerate().ToArray()))
{
@@ -207,31 +205,31 @@ internal class WikiAvatarViewModel : Abstraction.ViewModel
if (value == "火" || value == "水" || value == "草" || value == "雷" || value == "冰" || value == "风" || value == "岩")
{
keep = keep || avatar.FetterInfo.VisionBefore == value;
keep = keep && avatar.FetterInfo.VisionBefore == value;
continue;
}
if (IntrinsicImmutables.AssociationTypes.Contains(value))
{
keep = keep || avatar.FetterInfo.Association.GetDescriptionOrNull() == value;
keep = keep && avatar.FetterInfo.Association.GetDescriptionOrNull() == value;
continue;
}
if (IntrinsicImmutables.WeaponTypes.Contains(value))
{
keep = keep || avatar.Weapon.GetDescriptionOrNull() == value;
keep = keep && avatar.Weapon.GetDescriptionOrNull() == value;
continue;
}
if (IntrinsicImmutables.ItemQualities.Contains(value))
{
keep = keep || avatar.Quality.GetDescriptionOrNull() == value;
keep = keep && avatar.Quality.GetDescriptionOrNull() == value;
continue;
}
if (IntrinsicImmutables.BodyTypes.Contains(value))
{
keep = keep || avatar.Body.GetDescriptionOrNull() == value;
keep = keep && avatar.Body.GetDescriptionOrNull() == value;
continue;
}

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.UI;
using Microsoft.Extensions.Primitives;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding.Cultivation;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Intrinsic;
@@ -49,14 +48,13 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
/// </summary>
/// <param name="metadataService">元数据服务</param>
/// <param name="hutaoCache">胡桃缓存</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public WikiWeaponViewModel(IMetadataService metadataService, IHutaoCache hutaoCache, IAsyncRelayCommandFactory asyncRelayCommandFactory)
public WikiWeaponViewModel(IMetadataService metadataService, IHutaoCache hutaoCache)
{
this.metadataService = metadataService;
this.hutaoCache = hutaoCache;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
CultivateCommand = asyncRelayCommandFactory.Create<Weapon>(CultivateAsync);
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand<Weapon>(CultivateAsync);
FilterCommand = new RelayCommand<string>(ApplyFilter);
}
@@ -197,7 +195,7 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
private static bool DoFilter(string input, Weapon weapon)
{
bool keep = false;
bool keep = true;
foreach (StringSegment segment in new StringTokenizer(input, ' '.Enumerate().ToArray()))
{
@@ -205,19 +203,19 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
if (IntrinsicImmutables.WeaponTypes.Contains(value))
{
keep = keep || weapon.WeaponType.GetDescriptionOrNull() == value;
keep = keep && weapon.WeaponType.GetDescriptionOrNull() == value;
continue;
}
if (IntrinsicImmutables.ItemQualities.Contains(value))
{
keep = keep || weapon.Quality.GetDescriptionOrNull() == value;
keep = keep && weapon.Quality.GetDescriptionOrNull() == value;
continue;
}
if (IntrinsicImmutables.FightProperties.Contains(value))
{
keep = keep || weapon.Property.Properties.ElementAtOrDefault(1).GetDescriptionOrNull() == value;
keep = keep && weapon.Property.Properties.ElementAtOrDefault(1).GetDescriptionOrNull() == value;
continue;
}

View File

@@ -3,7 +3,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core.Convert;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Extension;
using Snap.Hutao.Model.Binding.User;
@@ -125,7 +124,7 @@ public class MiHoYoJSInterface
string salt = Core.CoreEnvironment.DynamicSecrets[nameof(SaltType.LK2)];
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
string r = GetRandomString();
string check = Md5Convert.ToHexString($"salt={salt}&t={t}&r={r}").ToLowerInvariant();
string check = Core.Convert.ToMd5HexString($"salt={salt}&t={t}&r={r}").ToLowerInvariant();
return new() { Data = new() { ["DS"] = $"{t},{r},{check}", }, };
@@ -157,7 +156,7 @@ public class MiHoYoJSInterface
int r = GetRandom();
string b = param.Payload.Body;
string q = param.Payload.GetQueryParam();
string check = Md5Convert.ToHexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
string check = Core.Convert.ToMd5HexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
return new() { Data = new() { ["DS"] = $"{t},{r},{check}" } };
@@ -257,8 +256,9 @@ public class MiHoYoJSInterface
return new() { Data = new() { ["statusBarHeight"] = 0 } };
}
public virtual IJsResult? PushPage(JsParam<PushPagePayload> param)
public virtual async Task<IJsResult?> PushPageAsync(JsParam<PushPagePayload> param)
{
await ThreadHelper.SwitchToMainThreadAsync();
webView.Navigate(param.Payload.Page);
return null;
}
@@ -370,7 +370,7 @@ public class MiHoYoJSInterface
"getUserInfo" => GetUserInfo(param),
"hideLoading" => null,
"login" => null,
"pushPage" => PushPage(param),
"pushPage" => await PushPageAsync(param).ConfigureAwait(false),
"showLoading" => null,
_ => logger.LogWarning<IJsResult>("Unhandled Message Type: {method}", param.Method),
};

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Convert;
using Snap.Hutao.Web.Request;
using System.Net.Http;
using System.Text;
@@ -46,7 +45,7 @@ public class DynamicSecretHandler : DelegatingHandler
dsContent = $"{dsContent}&b={b}&q={q}";
}
string check = Md5Convert.ToHexString(dsContent).ToLowerInvariant();
string check = Core.Convert.ToMd5HexString(dsContent).ToLowerInvariant();
request.Headers.Remove("DS-Option");
request.Headers.Set("DS", $"{t},{r},{check}");

View File

@@ -11,7 +11,6 @@ using Snap.Hutao.Web.Hutao.Model;
using Snap.Hutao.Web.Hutao.Model.Post;
using Snap.Hutao.Web.Response;
using System.Net.Http;
using System.Net.Http.Json;
namespace Snap.Hutao.Web.Hutao;

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Web.Bridge.Model;
@@ -10,7 +9,7 @@ namespace Snap.Hutao.Web.Response;
/// <summary>
/// 提供 <see cref="Response{T}"/> 的非泛型基类
/// </summary>
public class Response : ISupportValidation
public class Response
{
/// <summary>
/// 构造一个新的响应
@@ -64,12 +63,6 @@ public class Response : ISupportValidation
return response ?? new(0x26F19335, message, default);
}
/// <inheritdoc/>
public bool Validate()
{
return Enum.IsDefined(typeof(KnownReturnCode), ReturnCode);
}
/// <inheritdoc/>
public override string ToString()
{