diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml index 53814262..ab3ce5f4 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml @@ -43,8 +43,8 @@ 2 212 - 252 - 252 + 268 + 268 https://hut.ao/features/mhy-account-switch.html#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-cookie https://hut.ao/statements/bug-report.html diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs index 45518613..80801cdf 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs @@ -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; diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs b/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs new file mode 100644 index 00000000..71bcf6f1 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs @@ -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; + +/// +/// 纵横比控件 +/// +internal class AspectRatio : Microsoft.UI.Xaml.Controls.ContentControl +{ + private static readonly DependencyProperty TargetWidthProperty = Property.Depend(nameof(TargetWidth), 1D); + private static readonly DependencyProperty TargetHeightProperty = Property.Depend(nameof(TargetHeight), 1D); + + /// + /// 目标宽度 + /// + public double TargetWidth + { + get => (double)GetValue(TargetWidthProperty); + set => SetValue(TargetWidthProperty, value); + } + + /// + /// 目标高度 + /// + public double TargetHeight + { + get => (double)GetValue(TargetHeightProperty); + set => SetValue(TargetHeightProperty, value); + } + + /// + 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; + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs index 68466f95..6be2322a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs @@ -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; /// @@ -37,7 +37,7 @@ public class ScopedPage : Page where TViewModel : class, IViewModel { IViewModel viewModel = serviceScope.ServiceProvider.GetRequiredService(); - 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 } /// - [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(); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportAsyncInitialization.cs b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportAsyncInitialization.cs deleted file mode 100644 index 39c3fedb..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportAsyncInitialization.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Core.Abstraction; - -/// -/// 可异步初始化 -/// -internal interface ISupportAsyncInitialization -{ - /// - /// 是否已经初始化完成 - /// - public bool IsInitialized { get; } - - /// - /// 异步初始化 - /// - /// 取消令牌 - /// 初始化任务 - ValueTask InitializeAsync(); -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportValidation.cs b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportValidation.cs deleted file mode 100644 index d2dada6c..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/ISupportValidation.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Core.Abstraction; - -/// -/// 表示支持验证 -/// -internal interface ISupportValidation -{ - /// - /// 验证 - /// - /// 当前数据是否有效 - public bool Validate(); -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs index 47f85863..41e47120 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs @@ -25,7 +25,7 @@ public class ImageCache : IImageCache, IImageCacheFilePathOperation { private const string CacheFolderName = nameof(ImageCache); - private static readonly Dictionary RetryCountToDelay = new Dictionary() + private static readonly Dictionary RetryCountToDelay = new() { [0] = TimeSpan.FromSeconds(4), [1] = TimeSpan.FromSeconds(16), diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs b/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs similarity index 80% rename from src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs rename to src/Snap.Hutao/Snap.Hutao/Core/Convert.cs index e20f3c09..3842e83d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs @@ -4,19 +4,19 @@ using System.Security.Cryptography; using System.Text; -namespace Snap.Hutao.Core.Convert; +namespace Snap.Hutao.Core; /// /// 支持Md5转换 /// -internal abstract class Md5Convert +internal static class Convert { /// /// 获取字符串的MD5计算结果 /// /// 源字符串 /// 计算的结果 - 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); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs index 2b8f6162..92b8293f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs @@ -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 /// /// 米游社 Rpc 版本 /// - public const string HoyolabXrpcVersion = "2.43.1"; + public const string HoyolabXrpcVersion = "2.44.1"; /// /// 盐 @@ -39,8 +38,8 @@ internal static class CoreEnvironment // https://github.com/UIGF-org/Hoyolab.Salt public static readonly ImmutableDictionary DynamicSecrets = new Dictionary() { - [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() diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs index f6dd8cfc..33940299 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/PickerExtension.cs @@ -36,7 +36,7 @@ internal static class PickerExtension { Ioc.Default .GetRequiredService() - .Warning($"无法打开文件选择器 {exception.Message}"); + .Warning("无法打开文件选择器", $"请勿在管理员模式下使用此功能 {exception.Message}"); } return new(false, null!); @@ -68,7 +68,7 @@ internal static class PickerExtension { Ioc.Default .GetRequiredService() - .Warning($"无法打开文件选择器 {exception.Message}"); + .Warning("无法打开文件选择器", $"请勿在管理员模式下使用此功能 {exception.Message}"); } return new(false, null!); 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 40142bb0..5ddfcc75 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs @@ -11,8 +11,8 @@ internal class SeparatorCommaInt32EnumerableConverter : JsonConverter public override IEnumerable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - string? team = reader.GetString(); - IEnumerable? ids = team?.Split(',').Select(x => int.Parse(x)); + string? source = reader.GetString(); + IEnumerable? ids = source?.Split(',').Select(int.Parse); return ids ?? Enumerable.Empty(); } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs index 60c8161d..584e86d5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs @@ -10,6 +10,8 @@ namespace Snap.Hutao.Core.Json; /// internal class JsonTextEncoder : JavaScriptEncoder { + private static readonly string BackSlashDoubleQuote = "\\\""; + /// public override int MaxOutputCharactersPerInputCharacter { get => 6; } @@ -27,7 +29,7 @@ internal class JsonTextEncoder : JavaScriptEncoder if (unicodeScalar == '"') { numberOfCharactersWritten = 2; - return "\\\"".AsSpan().TryCopyTo(new Span(buffer, bufferLength)); + return BackSlashDoubleQuote.AsSpan().TryCopyTo(new Span(buffer, bufferLength)); } string encoded = $"\\u{(uint)unicodeScalar:x4}"; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs index 8cf91b96..6256358d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs @@ -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; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/CancellationTokenTaskCompletionSource.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/CancellationTokenTaskCompletionSource.cs deleted file mode 100644 index f4e0b5cf..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/CancellationTokenTaskCompletionSource.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Core.Threading; - -/// -/// Holds the task for a cancellation token, as well as the token registration. The registration is disposed when this instance is disposed. -/// -/// 包装类型 -public sealed class CancellationTokenTaskCompletionSource : IDisposable -{ - /// - /// The cancellation token registration, if any. This is null if the registration was not necessary. - /// - private readonly IDisposable? registration; - - /// - /// Creates a task for the specified cancellation token, registering with the token if necessary. - /// - /// The cancellation token to observe. - public CancellationTokenTaskCompletionSource(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - Task = Task.CompletedTask; - return; - } - - TaskCompletionSource tcs = new(); - registration = cancellationToken.Register(() => tcs.TrySetResult(), useSynchronizationContext: false); - Task = tcs.Task; - } - - /// - /// Gets the task for the source cancellation token. - /// - public Task Task { get; private set; } - - /// - /// Disposes the cancellation token registration, if any. Note that this may cause to never complete. - /// - public void Dispose() - { - registration?.Dispose(); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs index 8210bdc2..07d4e850 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs @@ -17,15 +17,13 @@ public static class DispatcherQueueExtension /// 执行的回调 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(); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs index b4c51158..e4c575ad 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs @@ -11,7 +11,7 @@ public enum BackdropType /// /// 无 /// - None = 0, + None, /// /// 亚克力 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs index dc0053f0..d84e756d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs @@ -148,6 +148,7 @@ internal sealed class ExtendedWindow : IRecipient(); messenger.Register(this); messenger.Register(this); + window.Closed += OnWindowClosed; } diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/BinaryReaderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/BinaryReaderExtension.cs deleted file mode 100644 index 606477ff..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Extension/BinaryReaderExtension.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using System.IO; - -namespace Snap.Hutao.Extension; - -/// -/// 扩展 -/// -public static class BinaryReaderExtension -{ - /// - /// 判断是否处于流的结尾 - /// - /// 读取器 - /// 是否处于流的结尾 - public static bool EndOfStream(this BinaryReader reader) - { - return reader.BaseStream.Position >= reader.BaseStream.Length; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/DateTimeOffsetExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/DateTimeOffsetExtension.cs index 8c0188a7..f939b0d2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/DateTimeOffsetExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/DateTimeOffsetExtension.cs @@ -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(); diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs index a8cfb3c0..0e39ba3c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs @@ -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 /// 源类型 /// 源 /// 源列表或空列表 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List EmptyIfNull(this List? source) { return source ?? new(); diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs index ba27babf..4db7cc49 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs @@ -9,13 +9,6 @@ namespace Snap.Hutao.Extension; [SuppressMessage("", "CA2254")] public static class LoggerExtension { - /// - public static T LogInformation(this ILogger logger, string message, params object?[] param) - { - logger.LogInformation(message, param); - return default!; - } - /// public static T LogWarning(this ILogger logger, string message, params object?[] param) { diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs index 8046cb24..50bc6e56 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using System.Runtime.CompilerServices; + namespace Snap.Hutao.Extension; /// @@ -8,36 +10,15 @@ namespace Snap.Hutao.Extension; /// public static class NumberExtension { - /// - /// 获取从右向左某位上的数字 - /// - /// 源 - /// 位 - /// 数字 - public static int AtPlace(this int x, int place) - { - return (int)(x / Math.Pow(10, place - 1)) % 10; - } - /// /// 计算给定整数的位数 /// /// 给定的整数 /// 位数 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Place(this int x) { // Benchmarked and compared as a most optimized solution return (int)(MathF.Log10(x) + 1); } - - /// - /// 计算给定整数的位数 - /// - /// 给定的整数 - /// 位数 - public static int Place(this long x) - { - // Benchmarked and compared as a most optimized solution - return (int)(MathF.Log10(x) + 1); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IAsyncRelayCommandFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IAsyncRelayCommandFactory.cs deleted file mode 100644 index 02f2469e..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IAsyncRelayCommandFactory.cs +++ /dev/null @@ -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; - -/// -/// Factory for creating with additional processing. -/// -public interface IAsyncRelayCommandFactory -{ - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The cancelable execution logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func cancelableExecute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The cancelable execution logic. - /// The execution status logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func cancelableExecute, Func canExecute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The execution logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func execute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The execution logic. - /// The execution status logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func execute, Func canExecute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The type of the command parameter. - /// The cancelable execution logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func cancelableExecute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The type of the command parameter. - /// The cancelable execution logic. - /// The execution status logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func cancelableExecute, Predicate canExecute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The type of the command parameter. - /// The execution logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func execute); - - /// - /// Create a reference to AsyncRelayCommand. - /// - /// The type of the command parameter. - /// The execution logic. - /// The execution status logic. - /// AsyncRelayCommand. - AsyncRelayCommand Create(Func execute, Predicate canExecute); -} diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs deleted file mode 100644 index 45c0c591..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Factory/AsyncRelayCommandFactory.cs +++ /dev/null @@ -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; - -/// -[Injection(InjectAs.Transient, typeof(IAsyncRelayCommandFactory))] -internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory -{ - private readonly ILogger logger; - - /// - /// 构造一个新的异步命令工厂 - /// - /// 日志器 - public AsyncRelayCommandFactory(ILogger logger) - { - this.logger = logger; - } - - /// - public AsyncRelayCommand Create(Func execute) - { - return Register(new AsyncRelayCommand(execute)); - } - - /// - public AsyncRelayCommand Create(Func cancelableExecute) - { - return Register(new AsyncRelayCommand(cancelableExecute)); - } - - /// - public AsyncRelayCommand Create(Func execute, Predicate canExecute) - { - return Register(new AsyncRelayCommand(execute, canExecute)); - } - - /// - public AsyncRelayCommand Create(Func cancelableExecute, Predicate canExecute) - { - return Register(new AsyncRelayCommand(cancelableExecute, canExecute)); - } - - /// - public AsyncRelayCommand Create(Func execute) - { - return Register(new AsyncRelayCommand(execute)); - } - - /// - public AsyncRelayCommand Create(Func cancelableExecute) - { - return Register(new AsyncRelayCommand(cancelableExecute)); - } - - /// - public AsyncRelayCommand Create(Func execute, Func canExecute) - { - return Register(new AsyncRelayCommand(execute, canExecute)); - } - - /// - public AsyncRelayCommand Create(Func cancelableExecute, Func canExecute) - { - return Register(new AsyncRelayCommand(cancelableExecute, canExecute)); - } - - private AsyncRelayCommand Register(AsyncRelayCommand command) - { - ReportException(command); - return command; - } - - private AsyncRelayCommand Register(AsyncRelayCommand 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)); - } - } - } - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs index 49721a6e..538106a0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs @@ -31,10 +31,10 @@ public class Costume /// /// 图标 /// - public string? Icon { get; set; } + public string Icon { get; set; } = default!; /// /// 侧面图标 /// - public string? SideIcon { get; set; } + public string SideIcon { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs index 61bf3544..37551378 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs @@ -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, + }, }; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs index b9bb62e6..d19a31b5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs @@ -34,6 +34,8 @@ internal class ElementNameIconConverter : ValueConverter return string.IsNullOrEmpty(element) ? Web.HutaoEndpoints.UIIconNone : new Uri(Web.HutaoEndpoints.StaticFile("IconElement", $"UI_Icon_Element_{element}.png")); + + // $"UI_Icon_Element_{element}.png" } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs index ce96c436..7e9e54c0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs @@ -6,7 +6,7 @@ using Snap.Hutao.Model.Metadata; namespace Snap.Hutao.Service.AvatarInfo.Factory; /// -/// 权重配置 +/// 圣遗物评分权重配置 /// internal static partial class ReliquaryWeightConfiguration { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs index 56de2214..bafb9562 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs @@ -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 equipments) { List reliquaryList = new(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs index 507d3d4f..3030a31f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs @@ -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; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs index 56fd454d..91a57941 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs @@ -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; /// [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); } - /// - public bool IsInitialized { get => isInitialized; private set => isInitialized = value; } - /// public async ValueTask InitializeAsync() { await initializeCompletionSource.Task.ConfigureAwait(false); - return IsInitialized; + return isInitialized; } /// @@ -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 FromCacheOrFileAsync(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> FromCacheAsDictionaryAsync(string fileName, Func 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> FromCacheAsDictionaryAsync(string fileName, Func keySelector, Func 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)) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs index 759094c6..2f51b46a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs @@ -97,8 +97,15 @@ internal class UserService : IUserService await ThreadHelper.SwitchToBackgroundAsync(); using (IServiceScope scope = scopeFactory.CreateScope()) { - // Note: cascade deleted dailynotes - await scope.ServiceProvider.GetRequiredService().Users.RemoveAndSaveAsync(user.Entity).ConfigureAwait(false); + try + { + // Note: cascade deleted dailynotes + await scope.ServiceProvider.GetRequiredService().Users.RemoveAndSaveAsync(user.Entity).ConfigureAwait(false); + } + catch (DbUpdateConcurrencyException ex) + { + throw new Core.ExceptionService.UserdataCorruptedException("用户已被其他功能删除", ex); + } } messenger.Send(new UserRemovedMessage(user.Entity)); diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index abe0a59b..6b5ffe17 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -154,7 +154,7 @@ - + @@ -182,7 +182,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementContentPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementContentPage.xaml.cs index 8094f9da..eed60ae4 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementContentPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementContentPage.xaml.cs @@ -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) diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml index e14257c0..bfbbea10 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml @@ -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 @@ - - + Style="{StaticResource BorderCardStyle}"> + + + + 成就服务 /// 信息条服务 /// Json序列化选项 - /// 异步命令工厂 /// 内容对话框工厂 /// 消息器 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(SearchAchievement); SortIncompletedSwitchCommand = new RelayCommand(UpdateAchievementsSort); SaveAchievementCommand = new RelayCommand(SaveAchievement); diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs index d1946821..d3562c4b 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs @@ -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 /// 构造一个公告视图模型 /// /// 公告服务 - /// 导航服务 - /// 异步命令工厂 - /// 信息条服务 - /// 日志器 - public AnnouncementViewModel(IAnnouncementService announcementService, IAsyncRelayCommandFactory asyncRelayCommandFactory) + public AnnouncementViewModel(IAnnouncementService announcementService) { this.announcementService = announcementService; - OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); OpenAnnouncementUICommand = new RelayCommand(OpenAnnouncementUI); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs index 7245feae..13706a31 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs @@ -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 /// 用户服务 /// 角色信息服务 /// 对话框工厂 - /// 异步命令工厂 /// 信息条服务 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(ExportAsImageAsync); - CultivateCommand = asyncRelayCommandFactory.Create(CultivateAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + RefreshFromEnkaApiCommand = new AsyncRelayCommand(RefreshByEnkaApiAsync); + RefreshFromHoyolabGameRecordCommand = new AsyncRelayCommand(RefreshByHoyolabGameRecordAsync); + RefreshFromHoyolabCalculateCommand = new AsyncRelayCommand(RefreshByHoyolabCalculateAsync); + ExportAsImageCommand = new AsyncRelayCommand(ExportAsImageAsync); + CultivateCommand = new AsyncRelayCommand(CultivateAsync); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/CultivationViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/CultivationViewModel.cs index 25381245..5b2d2994 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/CultivationViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/CultivationViewModel.cs @@ -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 /// /// 养成服务 /// 信息服务 - /// 异步命令工厂 /// 元数据服务 /// 日志器 public CultivationViewModel( ICultivationService cultivationService, IInfoBarService infoBarService, - IAsyncRelayCommandFactory asyncRelayCommandFactory, IMetadataService metadataService, ILogger 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(RemoveProjectAsync); - RemoveEntryCommand = asyncRelayCommandFactory.Create(RemoveEntryAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + AddProjectCommand = new AsyncRelayCommand(AddProjectAsync); + RemoveProjectCommand = new AsyncRelayCommand(RemoveProjectAsync); + RemoveEntryCommand = new AsyncRelayCommand(RemoveEntryAsync); SaveInventoryItemCommand = new RelayCommand(SaveInventoryItem); - UpdateStatisticsItemsCommand = asyncRelayCommandFactory.Create(UpdateStatisticsItemsAsync); + UpdateStatisticsItemsCommand = new AsyncRelayCommand(UpdateStatisticsItemsAsync); NavigateToPageCommand = new RelayCommand(NavigateToPage); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs index 2eff3677..7c8d8d49 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs @@ -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 /// 用户服务 /// 实时便笺服务 /// 数据库上下文 - /// 异步命令工厂 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(TrackRoleAsync); - RefreshCommand = asyncRelayCommandFactory.Create(RefreshAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + TrackRoleCommand = new AsyncRelayCommand(TrackRoleAsync); + RefreshCommand = new AsyncRelayCommand(RefreshAsync); RemoveDailyNoteCommand = new RelayCommand(RemoveDailyNote); - ModifyNotificationCommand = asyncRelayCommandFactory.Create(ModifyDailyNoteNotificationAsync); - DailyNoteVerificationCommand = asyncRelayCommandFactory.Create(VerifyDailyNoteVerificationAsync); + ModifyNotificationCommand = new AsyncRelayCommand(ModifyDailyNoteNotificationAsync); + DailyNoteVerificationCommand = new AsyncRelayCommand(VerifyDailyNoteVerificationAsync); } /// @@ -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().Error(ex); + return; + } + try { ThrowIfViewDisposed(); diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs index 3cb28db5..a754c227 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs @@ -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 /// /// 构造一个新的实验性功能视图模型 /// - /// 异步命令工厂 - 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); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs index 9e1280e1..07ab21bf 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs @@ -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 /// 祈愿记录服务 /// 信息 /// Json序列化选项 - /// 异步命令工厂 /// 内容对话框工厂 /// 文件选择器工厂 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); } /// @@ -202,24 +200,27 @@ internal class GachaLogViewModel : Abstraction.ViewModel Progress 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) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs index 3414b98b..f5fa0da4 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs @@ -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 /// 构造一个新的胡桃数据库视图模型 /// /// 胡桃服务缓存 - /// 异步命令工厂 - public HutaoDatabaseViewModel(IHutaoCache hutaoCache, IAsyncRelayCommandFactory asyncRelayCommandFactory) + public HutaoDatabaseViewModel(IHutaoCache hutaoCache) { this.hutaoCache = hutaoCache; - OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs index 56d066bf..7598df05 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs @@ -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 /// 游戏服务 /// 内存缓存 /// 数据库上下文 - /// 异步命令工厂 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(ModifyGameAccountAsync); - RemoveGameAccountCommand = asyncRelayCommandFactory.Create(RemoveGameAccountAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + LaunchCommand = new AsyncRelayCommand(LaunchAsync); + DetectGameAccountCommand = new AsyncRelayCommand(DetectGameAccountAsync); + ModifyGameAccountCommand = new AsyncRelayCommand(ModifyGameAccountAsync); + RemoveGameAccountCommand = new AsyncRelayCommand(RemoveGameAccountAsync); AttachGameAccountCommand = new RelayCommand(AttachGameAccountToCurrentUserGameRole); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs index a455fa40..db6c7bc4 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs @@ -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 /// /// 数据库上下文 /// 游戏服务 - /// 异步命令工厂 /// 实验性功能 /// 日志器 public SettingViewModel( AppDbContext appDbContext, IGameService gameService, - IAsyncRelayCommandFactory asyncRelayCommandFactory, ExperimentalFeaturesViewModel experimental, ILogger 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); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs index ecb7d1a6..71003861 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs @@ -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深渊记录服务 /// 元数据服务 /// 用户服务 - /// 异步命令工厂 /// 消息器 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); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs index a8790ebe..c19b1385 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs @@ -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 /// /// 构造一个新的测试视图模型 /// - /// 异步命令工厂 - 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); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs index 7d2268c6..20f8fb82 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs @@ -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 /// /// 用户服务 /// 信息条服务 - /// 异步命令工厂 - 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(RemoveUserAsync); + RemoveUserCommand = new AsyncRelayCommand(RemoveUserAsync); CopyCookieCommand = new RelayCommand(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) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WelcomeViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WelcomeViewModel.cs index 2619b9ee..350d6c51 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WelcomeViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WelcomeViewModel.cs @@ -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 /// /// 构造一个新的欢迎视图模型 /// - /// 异步命令工厂 /// 服务提供器 - public WelcomeViewModel(IAsyncRelayCommandFactory asyncRelayCommandFactory, IServiceProvider serviceProvider) + public WelcomeViewModel(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; - OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs index 36c56cbe..c74329fd 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs @@ -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 /// /// 元数据服务 /// 胡桃缓存 - /// 异步命令工厂 - 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(CultivateAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + CultivateCommand = new AsyncRelayCommand(CultivateAsync); FilterCommand = new RelayCommand(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; } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs index 38ab890b..0b503f9b 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs @@ -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 /// /// 元数据服务 /// 胡桃缓存 - /// 异步命令工厂 - 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(CultivateAsync); + OpenUICommand = new AsyncRelayCommand(OpenUIAsync); + CultivateCommand = new AsyncRelayCommand(CultivateAsync); FilterCommand = new RelayCommand(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; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs index 639b8b23..7d6ed485 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs @@ -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 param) + public virtual async Task PushPageAsync(JsParam 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("Unhandled Message Type: {method}", param.Method), }; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs index a6ae0b79..65007186 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs @@ -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}"); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs index 02ea534b..8071e744 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs @@ -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; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs index c554ebc3..dc78eb9e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/Response.cs @@ -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; /// /// 提供 的非泛型基类 /// -public class Response : ISupportValidation +public class Response { /// /// 构造一个新的响应 @@ -64,12 +63,6 @@ public class Response : ISupportValidation return response ?? new(0x26F19335, message, default); } - /// - public bool Validate() - { - return Enum.IsDefined(typeof(KnownReturnCode), ReturnCode); - } - /// public override string ToString() {