mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
remove async relay command factory
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
57
src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs
Normal file
57
src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
@@ -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()
|
||||
|
||||
@@ -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!);
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
|
||||
@@ -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}";
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public enum BackdropType
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
None = 0,
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 亚克力
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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!;
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -6,7 +6,7 @@ using Snap.Hutao.Model.Metadata;
|
||||
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||
|
||||
/// <summary>
|
||||
/// 权重配置
|
||||
/// 圣遗物评分权重配置
|
||||
/// </summary>
|
||||
internal static partial class ReliquaryWeightConfiguration
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user