mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
mapping abstraction
This commit is contained in:
@@ -74,7 +74,7 @@ public sealed partial class App : Application
|
|||||||
|
|
||||||
private void LogDiagnosticInformation()
|
private void LogDiagnosticInformation()
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
logger.LogInformation("FamilyName: {name}", hutaoOptions.FamilyName);
|
logger.LogInformation("FamilyName: {name}", hutaoOptions.FamilyName);
|
||||||
logger.LogInformation("Version: {version}", hutaoOptions.Version);
|
logger.LogInformation("Version: {version}", hutaoOptions.Version);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Snap.Hutao.Control.Image;
|
|||||||
internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Control
|
internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Control
|
||||||
{
|
{
|
||||||
private static readonly DependencyProperty SourceProperty = Property<CompositionImage>.Depend(nameof(Source), default(Uri), OnSourceChanged);
|
private static readonly DependencyProperty SourceProperty = Property<CompositionImage>.Depend(nameof(Source), default(Uri), OnSourceChanged);
|
||||||
private static readonly ConcurrentCancellationTokenSource<CompositionImage> LoadingTokenSource = new();
|
private readonly ConcurrentCancellationTokenSource loadingTokenSource = new();
|
||||||
|
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
|
|||||||
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
|
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
|
||||||
{
|
{
|
||||||
CompositionImage image = (CompositionImage)sender;
|
CompositionImage image = (CompositionImage)sender;
|
||||||
CancellationToken token = LoadingTokenSource.Register(image);
|
CancellationToken token = image.loadingTokenSource.Register();
|
||||||
IServiceProvider serviceProvider = image.serviceProvider;
|
IServiceProvider serviceProvider = image.serviceProvider;
|
||||||
ILogger<CompositionImage> logger = serviceProvider.GetRequiredService<ILogger<CompositionImage>>();
|
ILogger<CompositionImage> logger = serviceProvider.GetRequiredService<ILogger<CompositionImage>>();
|
||||||
|
|
||||||
|
|||||||
20
src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IMappingFrom.cs
Normal file
20
src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IMappingFrom.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.Abstraction;
|
||||||
|
|
||||||
|
internal interface IMappingFrom<TSelf, TFrom>
|
||||||
|
where TSelf : IMappingFrom<TSelf, TFrom>
|
||||||
|
{
|
||||||
|
[Pure]
|
||||||
|
static abstract TSelf From(TFrom source);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IMappingFrom<TSelf, T1, T2>
|
||||||
|
where TSelf : IMappingFrom<TSelf, T1, T2>
|
||||||
|
{
|
||||||
|
[Pure]
|
||||||
|
static abstract TSelf From(T1 t1, T2 t2);
|
||||||
|
}
|
||||||
@@ -221,7 +221,7 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
|||||||
return cacheFolder!;
|
return cacheFolder!;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseFolder ??= serviceProvider.GetRequiredService<HutaoOptions>().LocalCache;
|
baseFolder ??= serviceProvider.GetRequiredService<RuntimeOptions>().LocalCache;
|
||||||
DirectoryInfo info = Directory.CreateDirectory(Path.Combine(baseFolder, CacheFolderName));
|
DirectoryInfo info = Directory.CreateDirectory(Path.Combine(baseFolder, CacheFolderName));
|
||||||
cacheFolder = info.FullName;
|
cacheFolder = info.FullName;
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ internal static class IocConfiguration
|
|||||||
|
|
||||||
private static void AddDbContextCore(IServiceProvider provider, DbContextOptionsBuilder builder)
|
private static void AddDbContextCore(IServiceProvider provider, DbContextOptionsBuilder builder)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = provider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = provider.GetRequiredService<RuntimeOptions>();
|
||||||
string dbFile = System.IO.Path.Combine(hutaoOptions.DataFolder, "Userdata.db");
|
string dbFile = System.IO.Path.Combine(hutaoOptions.DataFolder, "Userdata.db");
|
||||||
string sqlConnectionString = $"Data Source={dbFile}";
|
string sqlConnectionString = $"Data Source={dbFile}";
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ internal static partial class IocHttpClientConfiguration
|
|||||||
/// <param name="client">配置后的客户端</param>
|
/// <param name="client">配置后的客户端</param>
|
||||||
private static void DefaultConfiguration(IServiceProvider serviceProvider, HttpClient client)
|
private static void DefaultConfiguration(IServiceProvider serviceProvider, HttpClient client)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
client.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ internal static class AppInstanceExtension
|
|||||||
|
|
||||||
ReadOnlySpan<HANDLE> handles = new(redirectEventHandle);
|
ReadOnlySpan<HANDLE> handles = new(redirectEventHandle);
|
||||||
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
||||||
|
|
||||||
|
// TODO: Release handle
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunAction(object? state)
|
private static void RunAction(object? state)
|
||||||
|
|||||||
@@ -8,30 +8,31 @@ using Snap.Hutao.Core.Setting;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using Windows.ApplicationModel;
|
using Windows.ApplicationModel;
|
||||||
|
using Windows.Foundation.Metadata;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core;
|
namespace Snap.Hutao.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 胡桃选项
|
|
||||||
/// 存储环境相关的选项
|
/// 存储环境相关的选项
|
||||||
/// 运行时运算得到的选项,无数据库交互
|
/// 运行时运算得到的选项,无数据库交互
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Injection(InjectAs.Singleton)]
|
[Injection(InjectAs.Singleton)]
|
||||||
internal sealed class HutaoOptions : IOptions<HutaoOptions>
|
internal sealed class RuntimeOptions : IOptions<RuntimeOptions>
|
||||||
{
|
{
|
||||||
private readonly ILogger<HutaoOptions> logger;
|
private readonly ILogger<RuntimeOptions> logger;
|
||||||
|
|
||||||
private readonly bool isWebView2Supported;
|
private readonly bool isWebView2Supported;
|
||||||
private readonly string webView2Version = SH.CoreWebView2HelperVersionUndetected;
|
private readonly string webView2Version = SH.CoreWebView2HelperVersionUndetected;
|
||||||
|
|
||||||
private bool? isElevated;
|
private bool? isElevated;
|
||||||
|
private bool? isWindows11;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的胡桃选项
|
/// 构造一个新的胡桃选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">日志器</param>
|
/// <param name="logger">日志器</param>
|
||||||
public HutaoOptions(ILogger<HutaoOptions> logger)
|
public RuntimeOptions(ILogger<RuntimeOptions> logger)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
|
||||||
@@ -97,8 +98,14 @@ internal sealed class HutaoOptions : IOptions<HutaoOptions>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsElevated { get => isElevated ??= GetElevated(); }
|
public bool IsElevated { get => isElevated ??= GetElevated(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统版本是否大于等于 Windows 11
|
||||||
|
/// %programfiles(x86)%\Windows Kits\10\Platforms\UAP\10.0.22000.0\PreviousPlatforms.xml
|
||||||
|
/// </summary>
|
||||||
|
public bool Windows11OrHigher { get => isWindows11 ?? ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 14); }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public HutaoOptions Value { get => this; }
|
public RuntimeOptions Value { get => this; }
|
||||||
|
|
||||||
private static string GetDataFolderPath()
|
private static string GetDataFolderPath()
|
||||||
{
|
{
|
||||||
@@ -13,12 +13,14 @@ internal sealed class FeatureOptions : IReadOnlyCollection<Feature>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启用实时便笺无感验证
|
/// 启用实时便笺无感验证
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Feature IsDailyNoteSilentVerificationEnabled { get; } = new("IsDailyNoteSilentVerificationEnabled", "启用实时便笺无感验证", "IsDailyNoteSilentVerificationEnabled", true);
|
public Feature IsDailyNoteSilentVerificationEnabled { get; } = new(
|
||||||
|
"IsDailyNoteSilentVerificationEnabled", "启用实时便笺无感验证", "IsDailyNoteSilentVerificationEnabled", true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 元数据检查是否忽略
|
/// 元数据检查是否忽略
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Feature IsMetadataUpdateCheckSuppressed { get; } = new("IsMetadataUpdateCheckSuppressed", "禁用元数据更新检查", "IsMetadataUpdateCheckSuppressed", false);
|
public Feature IsMetadataUpdateCheckSuppressed { get; } = new(
|
||||||
|
"IsMetadataUpdateCheckSuppressed", "禁用元数据更新检查", "IsMetadataUpdateCheckSuppressed", false);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int Count { get => 2; }
|
public int Count { get => 2; }
|
||||||
|
|||||||
@@ -49,35 +49,4 @@ internal static class SettingKeys
|
|||||||
/// 1.7.0 版本指引状态
|
/// 1.7.0 版本指引状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Major1Minor7Revision0GuideState = "Major1Minor7Revision0GuideState";
|
public const string Major1Minor7Revision0GuideState = "Major1Minor7Revision0GuideState";
|
||||||
|
|
||||||
#region StaticResource
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态资源合约
|
|
||||||
/// 新增合约时 请注意
|
|
||||||
/// <see cref="StaticResource.FulfillAllContracts"/>
|
|
||||||
/// 与 <see cref="StaticResource.IsAnyUnfulfilledContractPresent"/>
|
|
||||||
/// </summary>
|
|
||||||
public const string StaticResourceV1Contract = "StaticResourceV1Contract";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态资源合约V2 成就图标与物品图标
|
|
||||||
/// </summary>
|
|
||||||
public const string StaticResourceV2Contract = "StaticResourceV2Contract";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态资源合约V3 刷新 Skill Talent
|
|
||||||
/// </summary>
|
|
||||||
public const string StaticResourceV3Contract = "StaticResourceV3Contract";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态资源合约V4 刷新 AvatarIcon
|
|
||||||
/// </summary>
|
|
||||||
public const string StaticResourceV4Contract = "StaticResourceV4Contract";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态资源合约V5 刷新 AvatarIcon
|
|
||||||
/// </summary>
|
|
||||||
public const string StaticResourceV5Contract = "StaticResourceV5Contract";
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,31 @@ namespace Snap.Hutao.Core.Setting;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal static class StaticResource
|
internal static class StaticResource
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 静态资源合约
|
||||||
|
/// </summary>
|
||||||
|
public const string V1Contract = "StaticResourceV1Contract";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静态资源合约V2 成就图标与物品图标
|
||||||
|
/// </summary>
|
||||||
|
public const string V2Contract = "StaticResourceV2Contract";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静态资源合约V3 刷新 Skill Talent
|
||||||
|
/// </summary>
|
||||||
|
public const string V3Contract = "StaticResourceV3Contract";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静态资源合约V4 刷新 AvatarIcon
|
||||||
|
/// </summary>
|
||||||
|
public const string V4Contract = "StaticResourceV4Contract";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静态资源合约V5 刷新 AvatarIcon
|
||||||
|
/// </summary>
|
||||||
|
public const string V5Contract = "StaticResourceV5Contract";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 完成所有合约
|
/// 完成所有合约
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -41,18 +66,19 @@ internal static class StaticResource
|
|||||||
/// <returns>静态资源合约尚未完成</returns>
|
/// <returns>静态资源合约尚未完成</returns>
|
||||||
public static bool IsAnyUnfulfilledContractPresent()
|
public static bool IsAnyUnfulfilledContractPresent()
|
||||||
{
|
{
|
||||||
return !LocalSetting.Get(SettingKeys.StaticResourceV1Contract, false)
|
return !LocalSetting.Get(V1Contract, false)
|
||||||
|| (!LocalSetting.Get(SettingKeys.StaticResourceV2Contract, false))
|
|| (!LocalSetting.Get(V2Contract, false))
|
||||||
|| (!LocalSetting.Get(SettingKeys.StaticResourceV3Contract, false))
|
|| (!LocalSetting.Get(V3Contract, false))
|
||||||
|| (!LocalSetting.Get(SettingKeys.StaticResourceV4Contract, false));
|
|| (!LocalSetting.Get(V4Contract, false))
|
||||||
|
|| (!LocalSetting.Get(V5Contract, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetContractsState(bool state)
|
private static void SetContractsState(bool state)
|
||||||
{
|
{
|
||||||
LocalSetting.Set(SettingKeys.StaticResourceV1Contract, state);
|
LocalSetting.Set(V1Contract, state);
|
||||||
LocalSetting.Set(SettingKeys.StaticResourceV2Contract, state);
|
LocalSetting.Set(V2Contract, state);
|
||||||
LocalSetting.Set(SettingKeys.StaticResourceV3Contract, state);
|
LocalSetting.Set(V3Contract, state);
|
||||||
LocalSetting.Set(SettingKeys.StaticResourceV4Contract, state);
|
LocalSetting.Set(V4Contract, state);
|
||||||
LocalSetting.Set(SettingKeys.StaticResourceV5Contract, state);
|
LocalSetting.Set(V5Contract, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Threading;
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -24,31 +22,4 @@ internal class ConcurrentCancellationTokenSource
|
|||||||
source = new();
|
source = new();
|
||||||
return source.Token;
|
return source.Token;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 有区分项的并发<see cref="CancellationTokenSource"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TItem">项类型</typeparam>
|
|
||||||
[HighQuality]
|
|
||||||
[SuppressMessage("", "SA1402")]
|
|
||||||
internal class ConcurrentCancellationTokenSource<TItem>
|
|
||||||
where TItem : notnull
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<TItem, CancellationTokenSource> waitingItems = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 为某个项注册取消令牌
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">区分项</param>
|
|
||||||
/// <returns>取消令牌</returns>
|
|
||||||
public CancellationToken Register(TItem item)
|
|
||||||
{
|
|
||||||
if (waitingItems.TryRemove(item, out CancellationTokenSource? previousSource))
|
|
||||||
{
|
|
||||||
previousSource.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
return waitingItems.GetOrAdd(item, new CancellationTokenSource()).Token;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
namespace Snap.Hutao.Core.Threading;
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
[SuppressMessage("", "SA1201")]
|
|
||||||
internal readonly struct SemaphoreSlimToken : IDisposable
|
internal readonly struct SemaphoreSlimToken : IDisposable
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim semaphoreSlim;
|
private readonly SemaphoreSlim semaphoreSlim;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ internal sealed class TaskContext : ITaskContext
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void InvokeOnMainThread(Action action)
|
public void InvokeOnMainThread(Action action)
|
||||||
{
|
{
|
||||||
if (dispatcherQueue!.HasThreadAccess)
|
if (dispatcherQueue.HasThreadAccess)
|
||||||
{
|
{
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Threading;
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -30,7 +32,7 @@ internal static class TaskExtension
|
|||||||
{
|
{
|
||||||
if (System.Diagnostics.Debugger.IsAttached)
|
if (System.Diagnostics.Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
_ = ex;
|
System.Diagnostics.Debug.WriteLine(ExceptionFormat.Format(ex));
|
||||||
System.Diagnostics.Debugger.Break();
|
System.Diagnostics.Debugger.Break();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +60,7 @@ internal static class TaskExtension
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), e.GetBaseException());
|
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), ExceptionFormat.Format(e.GetBaseException()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ internal static class TaskExtension
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), e.GetBaseException());
|
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), ExceptionFormat.Format(e.GetBaseException()));
|
||||||
onException?.Invoke(e);
|
onException?.Invoke(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +106,7 @@ internal static class TaskExtension
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), e.GetBaseException());
|
logger?.LogError(e, "{Caller}:\r\n{Exception}", nameof(SafeForget), ExceptionFormat.Format(e.GetBaseException()));
|
||||||
onException?.Invoke(e);
|
onException?.Invoke(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,19 +52,4 @@ internal static class Must
|
|||||||
{
|
{
|
||||||
throw new NotSupportedException(context);
|
throw new NotSupportedException(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Throws an <see cref="ArgumentNullException"/> if the specified parameter's value is null.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the parameter.</typeparam>
|
|
||||||
/// <param name="value">The value of the argument.</param>
|
|
||||||
/// <param name="parameterName">The name of the parameter to include in any thrown exception.</param>
|
|
||||||
/// <returns>The value of the parameter.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is <c>null</c>.</exception>
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
public static T NotNull<T>([NotNull] T value, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
|
|
||||||
where T : class // ensures value-types aren't passed to a null checking method
|
|
||||||
{
|
|
||||||
return value ?? throw new ArgumentNullException(parameterName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutStateChangedMes
|
|||||||
|
|
||||||
private void InitializeWindow()
|
private void InitializeWindow()
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
WindowOptions options = window.WindowOptions;
|
WindowOptions options = window.WindowOptions;
|
||||||
window.AppWindow.Title = string.Format(SH.AppNameAndVersion, hutaoOptions.Version);
|
window.AppWindow.Title = string.Format(SH.AppNameAndVersion, hutaoOptions.Version);
|
||||||
@@ -73,7 +73,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutStateChangedMes
|
|||||||
// appWindow.Show(true);
|
// appWindow.Show(true);
|
||||||
// appWindow.Show can't bring window to top.
|
// appWindow.Show can't bring window to top.
|
||||||
window.Activate();
|
window.Activate();
|
||||||
Persistence.BringToForeground(options.Hwnd);
|
options.BringToForeground();
|
||||||
|
|
||||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||||
UpdateSystemBackdrop(appOptions.BackdropType);
|
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||||
@@ -182,7 +182,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutStateChangedMes
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
WindowOptions options = window.WindowOptions;
|
WindowOptions options = window.WindowOptions;
|
||||||
double scale = Persistence.GetScaleForWindowHandle(options.Hwnd);
|
double scale = options.GetWindowScale();
|
||||||
|
|
||||||
// 48 is the navigation button leftInset
|
// 48 is the navigation button leftInset
|
||||||
RectInt32 dragRect = StructMarshal.RectInt32(48, 0, options.TitleBar.ActualSize).Scale(scale);
|
RectInt32 dragRect = StructMarshal.RectInt32(48, 0, options.TitleBar.ActualSize).Scale(scale);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ internal static class Persistence
|
|||||||
WindowOptions options = window.WindowOptions;
|
WindowOptions options = window.WindowOptions;
|
||||||
|
|
||||||
// Set first launch size
|
// Set first launch size
|
||||||
double scale = GetScaleForWindowHandle(options.Hwnd);
|
double scale = options.GetWindowScale();
|
||||||
SizeInt32 transformedSize = options.InitSize.Scale(scale);
|
SizeInt32 transformedSize = options.InitSize.Scale(scale);
|
||||||
RectInt32 rect = StructMarshal.RectInt32(transformedSize);
|
RectInt32 rect = StructMarshal.RectInt32(transformedSize);
|
||||||
|
|
||||||
@@ -65,40 +65,6 @@ internal static class Persistence
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取窗体当前的DPI缩放比
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hwnd">窗体句柄</param>
|
|
||||||
/// <returns>缩放比</returns>
|
|
||||||
public static double GetScaleForWindowHandle(in HWND hwnd)
|
|
||||||
{
|
|
||||||
uint dpi = GetDpiForWindow(hwnd);
|
|
||||||
return Math.Round(dpi / 96D, 2, MidpointRounding.AwayFromZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将窗口设为前台窗口
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hwnd">窗口句柄</param>
|
|
||||||
public static unsafe void BringToForeground(in HWND hwnd)
|
|
||||||
{
|
|
||||||
HWND fgHwnd = GetForegroundWindow();
|
|
||||||
|
|
||||||
uint threadIdHwnd = GetWindowThreadProcessId(hwnd);
|
|
||||||
uint threadIdFgHwnd = GetWindowThreadProcessId(fgHwnd);
|
|
||||||
|
|
||||||
if (threadIdHwnd != threadIdFgHwnd)
|
|
||||||
{
|
|
||||||
AttachThreadInput(threadIdHwnd, threadIdFgHwnd, true);
|
|
||||||
SetForegroundWindow(hwnd);
|
|
||||||
AttachThreadInput(threadIdHwnd, threadIdFgHwnd, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetForegroundWindow(hwnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TransformToCenterScreen(ref RectInt32 rect)
|
private static void TransformToCenterScreen(ref RectInt32 rect)
|
||||||
{
|
{
|
||||||
DisplayArea displayArea = DisplayArea.GetFromRect(rect, DisplayAreaFallback.Primary);
|
DisplayArea displayArea = DisplayArea.GetFromRect(rect, DisplayAreaFallback.Primary);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Microsoft.UI.Xaml;
|
|||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using WinRT.Interop;
|
using WinRT.Interop;
|
||||||
|
using static Windows.Win32.PInvoke;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Windowing;
|
namespace Snap.Hutao.Core.Windowing;
|
||||||
|
|
||||||
@@ -53,4 +54,37 @@ internal readonly struct WindowOptions
|
|||||||
InitSize = initSize;
|
InitSize = initSize;
|
||||||
PersistSize = persistSize;
|
PersistSize = persistSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取窗体当前的DPI缩放比
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>缩放比</returns>
|
||||||
|
public double GetWindowScale()
|
||||||
|
{
|
||||||
|
uint dpi = GetDpiForWindow(Hwnd);
|
||||||
|
return Math.Round(dpi / 96D, 2, MidpointRounding.AwayFromZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将窗口设为前台窗口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hwnd">窗口句柄</param>
|
||||||
|
public unsafe void BringToForeground()
|
||||||
|
{
|
||||||
|
HWND fgHwnd = GetForegroundWindow();
|
||||||
|
|
||||||
|
uint threadIdHwnd = GetWindowThreadProcessId(Hwnd);
|
||||||
|
uint threadIdFgHwnd = GetWindowThreadProcessId(fgHwnd);
|
||||||
|
|
||||||
|
if (threadIdHwnd != threadIdFgHwnd)
|
||||||
|
{
|
||||||
|
AttachThreadInput(threadIdHwnd, threadIdFgHwnd, true);
|
||||||
|
SetForegroundWindow(Hwnd);
|
||||||
|
AttachThreadInput(threadIdHwnd, threadIdFgHwnd, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetForegroundWindow(Hwnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,8 @@ internal sealed class WindowSubclass<TWindow> : IDisposable
|
|||||||
{
|
{
|
||||||
case WM_GETMINMAXINFO:
|
case WM_GETMINMAXINFO:
|
||||||
{
|
{
|
||||||
double scalingFactor = Persistence.GetScaleForWindowHandle(hwnd);
|
uint dpi = GetDpiForWindow(hwnd);
|
||||||
|
double scalingFactor = Math.Round(dpi / 96D, 2, MidpointRounding.AwayFromZero);
|
||||||
window.ProcessMinMaxInfo((MINMAXINFO*)lParam.Value, scalingFactor);
|
window.ProcessMinMaxInfo((MINMAXINFO*)lParam.Value, scalingFactor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ internal static partial class EnumerableExtension
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
||||||
public static Dictionary<TKey, TSource> ToDictionaryOverride<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
public static Dictionary<TKey, TSource> ToDictionaryIgnoringDuplicateKeys<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
Dictionary<TKey, TSource> dictionary = new();
|
Dictionary<TKey, TSource> dictionary = new();
|
||||||
@@ -80,14 +80,14 @@ internal static partial class EnumerableExtension
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey, TElement}(IEnumerable{TSource}, Func{TSource, TKey}, Func{TSource, TElement})"/>
|
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey, TElement}(IEnumerable{TSource}, Func{TSource, TKey}, Func{TSource, TElement})"/>
|
||||||
public static Dictionary<TKey, TValue> ToDictionaryOverride<TKey, TValue, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
|
public static Dictionary<TKey, TValue> ToDictionaryIgnoringDuplicateKeys<TKey, TValue, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> elementSelector)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
Dictionary<TKey, TValue> dictionary = new();
|
Dictionary<TKey, TValue> dictionary = new();
|
||||||
|
|
||||||
foreach (TSource value in source)
|
foreach (TSource value in source)
|
||||||
{
|
{
|
||||||
dictionary[keySelector(value)] = valueSelector(value);
|
dictionary[keySelector(value)] = elementSelector(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dictionary;
|
return dictionary;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ internal static partial class EnumerableExtension
|
|||||||
/// <typeparam name="TSource">源的类型</typeparam>
|
/// <typeparam name="TSource">源的类型</typeparam>
|
||||||
/// <param name="source">源</param>
|
/// <param name="source">源</param>
|
||||||
/// <returns>集合</returns>
|
/// <returns>集合</returns>
|
||||||
|
[Obsolete("Use C# 12 Collection Literal instead")]
|
||||||
public static IEnumerable<TSource> Enumerate<TSource>(this TSource source)
|
public static IEnumerable<TSource> Enumerate<TSource>(this TSource source)
|
||||||
{
|
{
|
||||||
yield return source;
|
yield return source;
|
||||||
|
|||||||
@@ -16,13 +16,12 @@ internal static class ObjectExtension
|
|||||||
/// <typeparam name="T">数据类型</typeparam>
|
/// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="source">源</param>
|
/// <param name="source">源</param>
|
||||||
/// <returns>数组</returns>
|
/// <returns>数组</returns>
|
||||||
[Obsolete("Use C# 12 Collection Literals")]
|
[Obsolete("Use C# 12 Collection Literals when we migrate")]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T[] ToArray<T>(this T source)
|
public static T[] ToArray<T>(this T source)
|
||||||
{
|
{
|
||||||
// TODO: use C# 12 collection literals
|
// TODO: use C# 12 collection literals
|
||||||
// [ source ]
|
// [ source ]
|
||||||
// and mark this as Obsolete
|
|
||||||
return new[] { source };
|
return new[] { source };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ internal interface IContentDialogFactory
|
|||||||
/// <param name="title">标题</param>
|
/// <param name="title">标题</param>
|
||||||
/// <param name="content">内容</param>
|
/// <param name="content">内容</param>
|
||||||
/// <returns>结果</returns>
|
/// <returns>结果</returns>
|
||||||
ValueTask<ContentDialogResult> ConfirmAsync(string title, string content);
|
ValueTask<ContentDialogResult> CreateForConfirmAsync(string title, string content);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步确认或取消
|
/// 异步确认或取消
|
||||||
@@ -26,7 +26,7 @@ internal interface IContentDialogFactory
|
|||||||
/// <param name="content">内容</param>
|
/// <param name="content">内容</param>
|
||||||
/// <param name="defaultButton">默认按钮</param>
|
/// <param name="defaultButton">默认按钮</param>
|
||||||
/// <returns>结果</returns>
|
/// <returns>结果</returns>
|
||||||
ValueTask<ContentDialogResult> ConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close);
|
ValueTask<ContentDialogResult> CreateForConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步创建一个新的内容对话框,用于提示未知的进度
|
/// 异步创建一个新的内容对话框,用于提示未知的进度
|
||||||
|
|||||||
@@ -26,18 +26,35 @@ internal sealed class ContentDialogFactory : IContentDialogFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ContentDialogResult> ConfirmAsync(string title, string content)
|
public async ValueTask<ContentDialogResult> CreateForConfirmAsync(string title, string content)
|
||||||
{
|
{
|
||||||
ContentDialog dialog = await CreateForConfirmAsync(title, content).ConfigureAwait(false);
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
ContentDialog dialog = new()
|
||||||
|
{
|
||||||
|
XamlRoot = mainWindow.Content.XamlRoot,
|
||||||
|
Title = title,
|
||||||
|
Content = content,
|
||||||
|
DefaultButton = ContentDialogButton.Primary,
|
||||||
|
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
||||||
|
};
|
||||||
|
|
||||||
return await dialog.ShowAsync();
|
return await dialog.ShowAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ContentDialogResult> ConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close)
|
public async ValueTask<ContentDialogResult> CreateForConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close)
|
||||||
{
|
{
|
||||||
ContentDialog dialog = await CreateForConfirmCancelAsync(title, content, defaultButton).ConfigureAwait(false);
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
ContentDialog dialog = new()
|
||||||
|
{
|
||||||
|
XamlRoot = mainWindow.Content.XamlRoot,
|
||||||
|
Title = title,
|
||||||
|
Content = content,
|
||||||
|
DefaultButton = defaultButton,
|
||||||
|
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
||||||
|
CloseButtonText = SH.ContentDialogCancelCloseButtonText,
|
||||||
|
};
|
||||||
|
|
||||||
return await dialog.ShowAsync();
|
return await dialog.ShowAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,35 +71,4 @@ internal sealed class ContentDialogFactory : IContentDialogFactory
|
|||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask<ContentDialog> CreateForConfirmAsync(string title, string content)
|
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
ContentDialog dialog = new()
|
|
||||||
{
|
|
||||||
XamlRoot = mainWindow.Content.XamlRoot,
|
|
||||||
Title = title,
|
|
||||||
Content = content,
|
|
||||||
DefaultButton = ContentDialogButton.Primary,
|
|
||||||
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
|
||||||
};
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ValueTask<ContentDialog> CreateForConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close)
|
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
ContentDialog dialog = new()
|
|
||||||
{
|
|
||||||
XamlRoot = mainWindow.Content.XamlRoot,
|
|
||||||
Title = title,
|
|
||||||
Content = content,
|
|
||||||
DefaultButton = defaultButton,
|
|
||||||
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
|
||||||
CloseButtonText = SH.ContentDialogCancelCloseButtonText,
|
|
||||||
};
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
using Windows.Foundation.Metadata;
|
|
||||||
using Windows.Storage.Pickers;
|
using Windows.Storage.Pickers;
|
||||||
using WinRT.Interop;
|
using WinRT.Interop;
|
||||||
|
|
||||||
@@ -10,21 +10,14 @@ namespace Snap.Hutao.Factory;
|
|||||||
|
|
||||||
/// <inheritdoc cref="IPickerFactory"/>
|
/// <inheritdoc cref="IPickerFactory"/>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
|
[ConstructorGenerated]
|
||||||
[Injection(InjectAs.Transient, typeof(IPickerFactory))]
|
[Injection(InjectAs.Transient, typeof(IPickerFactory))]
|
||||||
internal class PickerFactory : IPickerFactory
|
internal sealed partial class PickerFactory : IPickerFactory
|
||||||
{
|
{
|
||||||
private const string AnyType = "*";
|
private const string AnyType = "*";
|
||||||
|
|
||||||
private readonly MainWindow mainWindow;
|
private readonly MainWindow mainWindow;
|
||||||
|
private readonly RuntimeOptions runtimeOptions;
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的文件选择器工厂
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mainWindow">主窗体的引用注入</param>
|
|
||||||
public PickerFactory(MainWindow mainWindow)
|
|
||||||
{
|
|
||||||
this.mainWindow = mainWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commitButton, params string[] fileTypes)
|
public FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commitButton, params string[] fileTypes)
|
||||||
@@ -40,7 +33,7 @@ internal class PickerFactory : IPickerFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
// below Windows 11
|
// below Windows 11
|
||||||
if (!ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 13))
|
if (!runtimeOptions.Windows11OrHigher)
|
||||||
{
|
{
|
||||||
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||||
picker.FileTypeFilter.Add(AnyType);
|
picker.FileTypeFilter.Add(AnyType);
|
||||||
@@ -72,7 +65,7 @@ internal class PickerFactory : IPickerFactory
|
|||||||
FolderPicker picker = GetInitializedPicker<FolderPicker>();
|
FolderPicker picker = GetInitializedPicker<FolderPicker>();
|
||||||
|
|
||||||
// below Windows 11
|
// below Windows 11
|
||||||
if (!ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 13))
|
if (!runtimeOptions.Windows11OrHigher)
|
||||||
{
|
{
|
||||||
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||||
picker.FileTypeFilter.Add(AnyType);
|
picker.FileTypeFilter.Add(AnyType);
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
@@ -13,7 +15,11 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
/// 可计算角色
|
/// 可计算角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
internal sealed class CalculableAvatar
|
||||||
|
: ObservableObject,
|
||||||
|
ICalculableAvatar,
|
||||||
|
IMappingFrom<CalculableAvatar, Avatar>,
|
||||||
|
IMappingFrom<CalculableAvatar, AvatarView>
|
||||||
{
|
{
|
||||||
private uint levelCurrent;
|
private uint levelCurrent;
|
||||||
private uint levelTarget;
|
private uint levelTarget;
|
||||||
@@ -22,7 +28,7 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
/// 构造一个新的可计算角色
|
/// 构造一个新的可计算角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="avatar">角色</param>
|
/// <param name="avatar">角色</param>
|
||||||
public CalculableAvatar(Metadata.Avatar.Avatar avatar)
|
private CalculableAvatar(Avatar avatar)
|
||||||
{
|
{
|
||||||
AvatarId = avatar.Id;
|
AvatarId = avatar.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
@@ -40,7 +46,7 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
/// 构造一个新的可计算角色
|
/// 构造一个新的可计算角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="avatar">角色</param>
|
/// <param name="avatar">角色</param>
|
||||||
public CalculableAvatar(AvatarView avatar)
|
private CalculableAvatar(AvatarView avatar)
|
||||||
{
|
{
|
||||||
AvatarId = avatar.Id;
|
AvatarId = avatar.Id;
|
||||||
LevelMin = avatar.LevelNumber;
|
LevelMin = avatar.LevelNumber;
|
||||||
@@ -80,4 +86,14 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
|
|
||||||
|
public static CalculableAvatar From(Avatar source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CalculableAvatar From(AvatarView source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,18 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可计算物品选项
|
/// 可计算物品选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class CalculableOptions
|
internal readonly struct CalculableOptions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色
|
||||||
|
/// </summary>
|
||||||
|
public readonly ICalculableAvatar? Avatar;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器
|
||||||
|
/// </summary>
|
||||||
|
public readonly ICalculableWeapon? Weapon;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的可计算物品选项
|
/// 构造一个新的可计算物品选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -18,14 +28,4 @@ internal sealed class CalculableOptions
|
|||||||
Avatar = avatar;
|
Avatar = avatar;
|
||||||
Weapon = weapon;
|
Weapon = weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色
|
|
||||||
/// </summary>
|
|
||||||
public ICalculableAvatar? Avatar { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器
|
|
||||||
/// </summary>
|
|
||||||
public ICalculableWeapon? Weapon { get; }
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
@@ -14,7 +15,11 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
/// 可计算的技能
|
/// 可计算的技能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
internal sealed class CalculableSkill
|
||||||
|
: ObservableObject,
|
||||||
|
ICalculableSkill,
|
||||||
|
IMappingFrom<CalculableSkill, ProudableSkill>,
|
||||||
|
IMappingFrom<CalculableSkill, SkillView>
|
||||||
{
|
{
|
||||||
private uint levelCurrent;
|
private uint levelCurrent;
|
||||||
private uint levelTarget;
|
private uint levelTarget;
|
||||||
@@ -23,7 +28,7 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
/// 构造一个新的可计算的技能
|
/// 构造一个新的可计算的技能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="skill">技能</param>
|
/// <param name="skill">技能</param>
|
||||||
public CalculableSkill(ProudableSkill skill)
|
private CalculableSkill(ProudableSkill skill)
|
||||||
{
|
{
|
||||||
GroupId = skill.GroupId;
|
GroupId = skill.GroupId;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
@@ -40,7 +45,7 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
/// 构造一个新的可计算的技能
|
/// 构造一个新的可计算的技能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="skill">技能</param>
|
/// <param name="skill">技能</param>
|
||||||
public CalculableSkill(SkillView skill)
|
private CalculableSkill(SkillView skill)
|
||||||
{
|
{
|
||||||
GroupId = skill.GroupId;
|
GroupId = skill.GroupId;
|
||||||
LevelMin = skill.LevelNumber;
|
LevelMin = skill.LevelNumber;
|
||||||
@@ -76,4 +81,14 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
|
|
||||||
|
public static CalculableSkill From(ProudableSkill source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CalculableSkill From(SkillView source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,10 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
|
|
||||||
@@ -13,7 +15,11 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
/// 可计算武器
|
/// 可计算武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
internal sealed class CalculableWeapon
|
||||||
|
: ObservableObject,
|
||||||
|
ICalculableWeapon,
|
||||||
|
IMappingFrom<CalculableWeapon, Weapon>,
|
||||||
|
IMappingFrom<CalculableWeapon, WeaponView>
|
||||||
{
|
{
|
||||||
private uint levelCurrent;
|
private uint levelCurrent;
|
||||||
private uint levelTarget;
|
private uint levelTarget;
|
||||||
@@ -22,7 +28,7 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
/// 构造一个新的可计算武器
|
/// 构造一个新的可计算武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="weapon">武器</param>
|
/// <param name="weapon">武器</param>
|
||||||
public CalculableWeapon(Metadata.Weapon.Weapon weapon)
|
private CalculableWeapon(Weapon weapon)
|
||||||
{
|
{
|
||||||
WeaponId = weapon.Id;
|
WeaponId = weapon.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
@@ -39,7 +45,7 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
/// 构造一个新的可计算武器
|
/// 构造一个新的可计算武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="weapon">武器</param>
|
/// <param name="weapon">武器</param>
|
||||||
public CalculableWeapon(WeaponView weapon)
|
private CalculableWeapon(WeaponView weapon)
|
||||||
{
|
{
|
||||||
WeaponId = weapon.Id;
|
WeaponId = weapon.Id;
|
||||||
LevelMin = weapon.LevelNumber;
|
LevelMin = weapon.LevelNumber;
|
||||||
@@ -75,4 +81,14 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
|
|
||||||
|
public static CalculableWeapon From(Weapon source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CalculableWeapon From(WeaponView source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Entity.Abstraction;
|
||||||
|
|
||||||
|
internal interface IDbMappingForeignKeyFrom<TSource, TFrom>
|
||||||
|
{
|
||||||
|
[Pure]
|
||||||
|
static abstract TSource From(in Guid foreignKey, in TFrom from);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IDbMappingForeignKeyFrom<TSource, T1, T2>
|
||||||
|
{
|
||||||
|
[Pure]
|
||||||
|
static abstract TSource From(in Guid foreignKey, in T1 param1, in T2 param2);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity.Abstraction;
|
||||||
using Snap.Hutao.Model.InterChange.Achievement;
|
using Snap.Hutao.Model.InterChange.Achievement;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
@@ -14,7 +15,11 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("achievements")]
|
[Table("achievements")]
|
||||||
internal sealed class Achievement : IEquatable<Achievement>
|
[SuppressMessage("", "SA1124")]
|
||||||
|
internal sealed class Achievement
|
||||||
|
: IEquatable<Achievement>,
|
||||||
|
IDbMappingForeignKeyFrom<Achievement, AchievementId>,
|
||||||
|
IDbMappingForeignKeyFrom<Achievement, UIAFItem>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -57,14 +62,14 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个新的成就
|
/// 创建一个新的成就
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId">对应的用户id</param>
|
/// <param name="archiveId">对应的用户id</param>
|
||||||
/// <param name="id">成就Id</param>
|
/// <param name="id">成就Id</param>
|
||||||
/// <returns>新创建的成就</returns>
|
/// <returns>新创建的成就</returns>
|
||||||
public static Achievement Create(in Guid userId, in AchievementId id)
|
public static Achievement From(in Guid archiveId, in AchievementId id)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
ArchiveId = userId,
|
ArchiveId = archiveId,
|
||||||
Id = id,
|
Id = id,
|
||||||
Current = 0,
|
Current = 0,
|
||||||
Time = DateTimeOffset.MinValue,
|
Time = DateTimeOffset.MinValue,
|
||||||
@@ -77,7 +82,7 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
/// <param name="userId">对应的用户id</param>
|
/// <param name="userId">对应的用户id</param>
|
||||||
/// <param name="uiaf">uiaf项</param>
|
/// <param name="uiaf">uiaf项</param>
|
||||||
/// <returns>新创建的成就</returns>
|
/// <returns>新创建的成就</returns>
|
||||||
public static Achievement Create(in Guid userId, UIAFItem uiaf)
|
public static Achievement From(in Guid userId, in UIAFItem uiaf)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -89,21 +94,6 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换到UIAF物品
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>UIAF物品</returns>
|
|
||||||
public UIAFItem ToUIAFItem()
|
|
||||||
{
|
|
||||||
return new()
|
|
||||||
{
|
|
||||||
Id = Id,
|
|
||||||
Current = Current,
|
|
||||||
Status = Status,
|
|
||||||
Timestamp = Time.ToUnixTimeSeconds(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool Equals(Achievement? other)
|
public bool Equals(Achievement? other)
|
||||||
{
|
{
|
||||||
@@ -121,6 +111,8 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Object
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
@@ -132,4 +124,5 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
{
|
{
|
||||||
return HashCode.Combine(ArchiveId, Id, Current, Status, Time);
|
return HashCode.Combine(ArchiveId, Id, Current, Status, Time);
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@@ -11,7 +12,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// 成就存档
|
/// 成就存档
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Table("achievement_archives")]
|
[Table("achievement_archives")]
|
||||||
internal sealed class AchievementArchive : ISelectable
|
internal sealed class AchievementArchive : ISelectable, IMappingFrom<AchievementArchive, string>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -35,7 +36,7 @@ internal sealed class AchievementArchive : ISelectable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">名称</param>
|
/// <param name="name">名称</param>
|
||||||
/// <returns>新存档</returns>
|
/// <returns>新存档</returns>
|
||||||
public static AchievementArchive Create(string name)
|
public static AchievementArchive From(string name)
|
||||||
{
|
{
|
||||||
return new() { Name = name };
|
return new() { Name = name };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -11,10 +12,10 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("avatar_infos")]
|
[Table("avatar_infos")]
|
||||||
internal sealed class AvatarInfo
|
internal sealed class AvatarInfo : IMappingFrom<AvatarInfo, string, Web.Enka.Model.AvatarInfo>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部 Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Key]
|
[Key]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
@@ -36,7 +37,7 @@ internal sealed class AvatarInfo
|
|||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <param name="info">角色信息</param>
|
/// <param name="info">角色信息</param>
|
||||||
/// <returns>实体角色信息</returns>
|
/// <returns>实体角色信息</returns>
|
||||||
public static AvatarInfo Create(string uid, Web.Enka.Model.AvatarInfo info)
|
public static AvatarInfo From(string uid, Web.Enka.Model.AvatarInfo info)
|
||||||
{
|
{
|
||||||
return new() { Uid = uid, Info = info };
|
return new() { Uid = uid, Info = info };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal sealed class AvatarInfoConfiguration : IEntityTypeConfiguration<AvatarI
|
|||||||
public void Configure(EntityTypeBuilder<AvatarInfo> builder)
|
public void Configure(EntityTypeBuilder<AvatarInfo> builder)
|
||||||
{
|
{
|
||||||
builder.Property(e => e.Info)
|
builder.Property(e => e.Info)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion<JsonTextValueConverter<Web.Enka.Model.AvatarInfo>>();
|
.HasConversion<JsonTextValueConverter<Web.Enka.Model.AvatarInfo>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ internal sealed class DailyNoteEntryConfiguration : IEntityTypeConfiguration<Dai
|
|||||||
public void Configure(EntityTypeBuilder<DailyNoteEntry> builder)
|
public void Configure(EntityTypeBuilder<DailyNoteEntry> builder)
|
||||||
{
|
{
|
||||||
builder.Property(e => e.DailyNote)
|
builder.Property(e => e.DailyNote)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion<JsonTextValueConverter<Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote>>();
|
.HasConversion<JsonTextValueConverter<Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal sealed class InventoryReliquaryConfiguration : IEntityTypeConfiguration
|
|||||||
public void Configure(EntityTypeBuilder<InventoryReliquary> builder)
|
public void Configure(EntityTypeBuilder<InventoryReliquary> builder)
|
||||||
{
|
{
|
||||||
builder.Property(e => e.AppendPropIdList)
|
builder.Property(e => e.AppendPropIdList)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion(
|
.HasConversion(
|
||||||
list => list.ToString(','),
|
list => list.ToString(','),
|
||||||
text => text.Split(',', StringSplitOptions.None).Select(int.Parse).ToList());
|
text => text.Split(',', StringSplitOptions.None).Select(int.Parse).ToList());
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal sealed class SpiralAbyssEntryConfiguration : IEntityTypeConfiguration<S
|
|||||||
public void Configure(EntityTypeBuilder<SpiralAbyssEntry> builder)
|
public void Configure(EntityTypeBuilder<SpiralAbyssEntry> builder)
|
||||||
{
|
{
|
||||||
builder.Property(e => e.SpiralAbyss)
|
builder.Property(e => e.SpiralAbyss)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion<JsonTextValueConverter<Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss>>();
|
.HasConversion<JsonTextValueConverter<Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Entity.Configuration;
|
||||||
|
|
||||||
|
internal sealed class SqliteTypeNames
|
||||||
|
{
|
||||||
|
public const string Integer = "INTEGER";
|
||||||
|
public const string Real = "REAL";
|
||||||
|
public const string Blob = "BLOB";
|
||||||
|
public const string Text = "TEXT";
|
||||||
|
}
|
||||||
@@ -17,15 +17,15 @@ internal sealed class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
public void Configure(EntityTypeBuilder<User> builder)
|
public void Configure(EntityTypeBuilder<User> builder)
|
||||||
{
|
{
|
||||||
builder.Property(e => e.CookieToken)
|
builder.Property(e => e.CookieToken)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
||||||
|
|
||||||
builder.Property(e => e.LToken)
|
builder.Property(e => e.LToken)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
||||||
|
|
||||||
builder.Property(e => e.SToken)
|
builder.Property(e => e.SToken)
|
||||||
.HasColumnType("TEXT")
|
.HasColumnType(SqliteTypeNames.Text)
|
||||||
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
.HasConversion(e => e!.ToString(), e => Cookie.Parse(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity.Abstraction;
|
||||||
using Snap.Hutao.Model.Entity.Primitive;
|
using Snap.Hutao.Model.Entity.Primitive;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@@ -12,7 +13,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("cultivate_entries")]
|
[Table("cultivate_entries")]
|
||||||
internal sealed class CultivateEntry
|
internal sealed class CultivateEntry : IDbMappingForeignKeyFrom<CultivateEntry, CultivateType, uint>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -49,7 +50,7 @@ internal sealed class CultivateEntry
|
|||||||
/// <param name="type">类型</param>
|
/// <param name="type">类型</param>
|
||||||
/// <param name="id">主Id</param>
|
/// <param name="id">主Id</param>
|
||||||
/// <returns>养成入口点</returns>
|
/// <returns>养成入口点</returns>
|
||||||
public static CultivateEntry Create(in Guid projectId, CultivateType type, uint id)
|
public static CultivateEntry From(in Guid projectId, in CultivateType type, in uint id)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity.Abstraction;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("cultivate_items")]
|
[Table("cultivate_items")]
|
||||||
internal sealed class CultivateItem
|
internal sealed class CultivateItem : IDbMappingForeignKeyFrom<CultivateItem, Web.Hoyolab.Takumi.Event.Calculate.Item>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -50,16 +51,15 @@ internal sealed class CultivateItem
|
|||||||
/// 创建一个新的养成物品
|
/// 创建一个新的养成物品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entryId">入口点 Id</param>
|
/// <param name="entryId">入口点 Id</param>
|
||||||
/// <param name="itemId">物品 Id</param>
|
/// <param name="item">物品</param>
|
||||||
/// <param name="count">个数</param>
|
|
||||||
/// <returns>养成物品</returns>
|
/// <returns>养成物品</returns>
|
||||||
public static CultivateItem Create(in Guid entryId, int itemId, int count)
|
public static CultivateItem From(in Guid entryId, in Web.Hoyolab.Takumi.Event.Calculate.Item item)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
EntryId = entryId,
|
EntryId = entryId,
|
||||||
ItemId = itemId,
|
ItemId = item.Id,
|
||||||
Count = count,
|
Count = item.Num,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@@ -12,7 +13,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("cultivate_projects")]
|
[Table("cultivate_projects")]
|
||||||
internal sealed class CultivateProject : ISelectable
|
internal sealed class CultivateProject : ISelectable, IMappingFrom<CultivateProject, string, string>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -42,7 +43,7 @@ internal sealed class CultivateProject : ISelectable
|
|||||||
/// <param name="name">名称</param>
|
/// <param name="name">名称</param>
|
||||||
/// <param name="attachedUid">绑定的Uid</param>
|
/// <param name="attachedUid">绑定的Uid</param>
|
||||||
/// <returns>新的养成计划</returns>
|
/// <returns>新的养成计划</returns>
|
||||||
public static CultivateProject Create(string name, string? attachedUid = null)
|
public static CultivateProject From(string name, string? attachedUid = null)
|
||||||
{
|
{
|
||||||
return new() { Name = name, AttachedUid = attachedUid };
|
return new() { Name = name, AttachedUid = attachedUid };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
@@ -15,7 +16,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("daily_notes")]
|
[Table("daily_notes")]
|
||||||
internal sealed class DailyNoteEntry : ObservableObject
|
internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom<DailyNoteEntry, UserAndUid>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -106,7 +107,7 @@ internal sealed class DailyNoteEntry : ObservableObject
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userAndUid">用户与角色</param>
|
/// <param name="userAndUid">用户与角色</param>
|
||||||
/// <returns>新的实时便笺</returns>
|
/// <returns>新的实时便笺</returns>
|
||||||
public static DailyNoteEntry Create(UserAndUid userAndUid)
|
public static DailyNoteEntry From(UserAndUid userAndUid)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Service.GachaLog;
|
using Snap.Hutao.Service.GachaLog;
|
||||||
@@ -17,7 +18,7 @@ namespace Snap.Hutao.Model.Entity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Table("gacha_archives")]
|
[Table("gacha_archives")]
|
||||||
internal sealed class GachaArchive : ISelectable
|
internal sealed class GachaArchive : ISelectable, IMappingFrom<GachaArchive, string>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部Id
|
/// 内部Id
|
||||||
@@ -39,7 +40,7 @@ internal sealed class GachaArchive : ISelectable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <returns>新的卡池存档</returns>
|
/// <returns>新的卡池存档</returns>
|
||||||
public static GachaArchive Create(string uid)
|
public static GachaArchive From(string uid)
|
||||||
{
|
{
|
||||||
return new() { Uid = uid };
|
return new() { Uid = uid };
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ internal sealed class GachaArchive : ISelectable
|
|||||||
|
|
||||||
if (archive == null)
|
if (archive == null)
|
||||||
{
|
{
|
||||||
GachaArchive created = Create(context.Uid);
|
GachaArchive created = From(context.Uid);
|
||||||
context.GachaArchives.AddAndSave(created);
|
context.GachaArchives.AddAndSave(created);
|
||||||
context.TaskContext.InvokeOnMainThread(() => context.ArchiveCollection.Add(created));
|
context.TaskContext.InvokeOnMainThread(() => context.ArchiveCollection.Add(created));
|
||||||
archive = created;
|
archive = created;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ internal sealed class UIAFInfo
|
|||||||
/// <returns>专用 UIAF 信息</returns>
|
/// <returns>专用 UIAF 信息</returns>
|
||||||
public static UIAFInfo Create(IServiceProvider serviceProvider)
|
public static UIAFInfo Create(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.InterChange.Achievement;
|
namespace Snap.Hutao.Model.InterChange.Achievement;
|
||||||
@@ -8,7 +9,7 @@ namespace Snap.Hutao.Model.InterChange.Achievement;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// UIAF 项
|
/// UIAF 项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class UIAFItem
|
internal sealed class UIAFItem : IMappingFrom<UIAFItem, Entity.Achievement>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成就Id
|
/// 成就Id
|
||||||
@@ -34,4 +35,15 @@ internal sealed class UIAFItem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("status")]
|
[JsonPropertyName("status")]
|
||||||
public AchievementStatus Status { get; set; }
|
public AchievementStatus Status { get; set; }
|
||||||
|
|
||||||
|
public static UIAFItem From(Entity.Achievement source)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Id = source.Id,
|
||||||
|
Current = source.Current,
|
||||||
|
Status = source.Status,
|
||||||
|
Timestamp = source.Time.ToUnixTimeSeconds(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ internal sealed class UIGFInfo
|
|||||||
/// <returns>专用 UIGF 信息</returns>
|
/// <returns>专用 UIGF 信息</returns>
|
||||||
public static UIGFInfo Create(IServiceProvider serviceProvider, string uid)
|
public static UIGFInfo Create(IServiceProvider serviceProvider, string uid)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ internal sealed class UIIFInfo
|
|||||||
/// <returns>专用 UIGF 信息</returns>
|
/// <returns>专用 UIGF 信息</returns>
|
||||||
public static UIIFInfo Create(IServiceProvider serviceProvider, string uid)
|
public static UIIFInfo Create(IServiceProvider serviceProvider, string uid)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableAvatar(this);
|
return CalculableAvatar.From(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ internal sealed partial class ProudableSkill : ICalculableSource<ICalculableSkil
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableSkill ToCalculable()
|
public ICalculableSkill ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableSkill(this);
|
return CalculableSkill.From(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableWeapon ToCalculable()
|
public ICalculableWeapon ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableWeapon(this);
|
return CalculableWeapon.From(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ internal sealed partial class AchievementDbBulkOperation
|
|||||||
|
|
||||||
if (entity is null && uiaf is not null)
|
if (entity is null && uiaf is not null)
|
||||||
{
|
{
|
||||||
appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
|
appDbContext.Achievements.AddAndSave(EntityAchievement.From(archiveId, uiaf));
|
||||||
add++;
|
add++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ internal sealed partial class AchievementDbBulkOperation
|
|||||||
if (aggressive)
|
if (aggressive)
|
||||||
{
|
{
|
||||||
appDbContext.Achievements.RemoveAndSave(entity);
|
appDbContext.Achievements.RemoveAndSave(entity);
|
||||||
appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
|
appDbContext.Achievements.AddAndSave(EntityAchievement.From(archiveId, uiaf));
|
||||||
update++;
|
update++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ internal sealed partial class AchievementDbBulkOperation
|
|||||||
moveEntity = false;
|
moveEntity = false;
|
||||||
moveUIAF = true;
|
moveUIAF = true;
|
||||||
|
|
||||||
appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
|
appDbContext.Achievements.AddAndSave(EntityAchievement.From(archiveId, uiaf));
|
||||||
add++;
|
add++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ internal sealed partial class AchievementService
|
|||||||
case ImportStrategy.Overwrite:
|
case ImportStrategy.Overwrite:
|
||||||
{
|
{
|
||||||
IEnumerable<EntityAchievement> orederedUIAF = list
|
IEnumerable<EntityAchievement> orederedUIAF = list
|
||||||
.Select(uiaf => EntityAchievement.Create(archiveId, uiaf))
|
.Select(uiaf => EntityAchievement.From(archiveId, uiaf))
|
||||||
.OrderBy(a => a.Id);
|
.OrderBy(a => a.Id);
|
||||||
return achievementDbBulkOperation.Overwrite(archiveId, orederedUIAF);
|
return achievementDbBulkOperation.Overwrite(archiveId, orederedUIAF);
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ internal sealed partial class AchievementService
|
|||||||
List<UIAFItem> list = appDbContext.Achievements
|
List<UIAFItem> list = appDbContext.Achievements
|
||||||
.Where(i => i.ArchiveId == archive.InnerId)
|
.Where(i => i.ArchiveId == archive.InnerId)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Select(i => i.ToUIAFItem())
|
.Select(UIAFItem.From)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ internal sealed partial class AchievementService : IAchievementService
|
|||||||
|
|
||||||
return metadata.SelectList(meta =>
|
return metadata.SelectList(meta =>
|
||||||
{
|
{
|
||||||
EntityAchievement entity = entityMap.GetValueOrDefault(meta.Id) ?? EntityAchievement.Create(archive.InnerId, meta.Id);
|
EntityAchievement entity = entityMap.GetValueOrDefault(meta.Id) ?? EntityAchievement.From(archive.InnerId, meta.Id);
|
||||||
return new AchievementView(entity, meta);
|
return new AchievementView(entity, meta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
{
|
{
|
||||||
EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId };
|
EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId };
|
||||||
transformer.Transform(ref avatarInfo, source);
|
transformer.Transform(ref avatarInfo, source);
|
||||||
entity = ModelAvatarInfo.Create(uid, avatarInfo);
|
entity = ModelAvatarInfo.From(uid, avatarInfo);
|
||||||
appDbContext.AvatarInfos.AddAndSave(entity);
|
appDbContext.AvatarInfos.AddAndSave(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -221,7 +221,7 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
{
|
{
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
entity = ModelAvatarInfo.Create(uid, webInfo);
|
entity = ModelAvatarInfo.From(uid, webInfo);
|
||||||
appDbContext.AvatarInfos.AddAndSave(entity);
|
appDbContext.AvatarInfos.AddAndSave(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -222,14 +222,14 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
|
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
{
|
{
|
||||||
entry = CultivateEntry.Create(projectId, type, itemId);
|
entry = CultivateEntry.From(projectId, type, itemId);
|
||||||
await appDbContext.CultivateEntries.AddAndSaveAsync(entry).ConfigureAwait(false);
|
await appDbContext.CultivateEntries.AddAndSaveAsync(entry).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Guid entryId = entry.InnerId;
|
Guid entryId = entry.InnerId;
|
||||||
await appDbContext.CultivateItems.ExecuteDeleteWhereAsync(i => i.EntryId == entryId).ConfigureAwait(false);
|
await appDbContext.CultivateItems.ExecuteDeleteWhereAsync(i => i.EntryId == entryId).ConfigureAwait(false);
|
||||||
|
|
||||||
IEnumerable<CultivateItem> toAdd = items.Select(i => CultivateItem.Create(entryId, i.Id, i.Num));
|
IEnumerable<CultivateItem> toAdd = items.Select(item => CultivateItem.From(entryId, item));
|
||||||
await appDbContext.CultivateItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
await appDbContext.CultivateItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
|
|
||||||
if (!appDbContext.DailyNotes.Any(n => n.Uid == roleUid))
|
if (!appDbContext.DailyNotes.Any(n => n.Uid == roleUid))
|
||||||
{
|
{
|
||||||
DailyNoteEntry newEntry = DailyNoteEntry.Create(role);
|
DailyNoteEntry newEntry = DailyNoteEntry.From(role);
|
||||||
|
|
||||||
Web.Response.Response<WebDailyNote> dailyNoteResponse = await scope.ServiceProvider
|
Web.Response.Response<WebDailyNote> dailyNoteResponse = await scope.ServiceProvider
|
||||||
.PickRequiredService<IGameRecordClient>(PlayerUid.IsOversea(roleUid))
|
.PickRequiredService<IGameRecordClient>(PlayerUid.IsOversea(roleUid))
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ internal sealed partial class HutaoCloudService : IHutaoCloudService
|
|||||||
{
|
{
|
||||||
if (archive == null)
|
if (archive == null)
|
||||||
{
|
{
|
||||||
archive = Model.Entity.GachaArchive.Create(uid);
|
archive = Model.Entity.GachaArchive.From(uid);
|
||||||
await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false);
|
await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ internal sealed partial class GameService : IGameService
|
|||||||
private readonly PackageConverter packageConverter;
|
private readonly PackageConverter packageConverter;
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly LaunchOptions launchOptions;
|
private readonly LaunchOptions launchOptions;
|
||||||
private readonly HutaoOptions hutaoOptions;
|
private readonly RuntimeOptions hutaoOptions;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly AppOptions appOptions;
|
private readonly AppOptions appOptions;
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ internal sealed partial class GameService : IGameService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask DetectGameAccountAsync()
|
public async ValueTask DetectGameAccountAsync()
|
||||||
{
|
{
|
||||||
Must.NotNull(gameAccounts!);
|
ArgumentNullException.ThrowIfNull(gameAccounts);
|
||||||
|
|
||||||
string? registrySdk = RegistryInterop.Get();
|
string? registrySdk = RegistryInterop.Get();
|
||||||
if (!string.IsNullOrEmpty(registrySdk))
|
if (!string.IsNullOrEmpty(registrySdk))
|
||||||
@@ -350,7 +350,7 @@ internal sealed partial class GameService : IGameService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public GameAccount? DetectCurrentGameAccount()
|
public GameAccount? DetectCurrentGameAccount()
|
||||||
{
|
{
|
||||||
Must.NotNull(gameAccounts!);
|
ArgumentNullException.ThrowIfNull(gameAccounts);
|
||||||
|
|
||||||
string? registrySdk = RegistryInterop.Get();
|
string? registrySdk = RegistryInterop.Get();
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ internal sealed partial class PackageConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache folder
|
// Cache folder
|
||||||
Core.HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<Core.HutaoOptions>();
|
Core.RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<Core.RuntimeOptions>();
|
||||||
string cacheFolder = Path.Combine(hutaoOptions.DataFolder, "ServerCache");
|
string cacheFolder = Path.Combine(hutaoOptions.DataFolder, "ServerCache");
|
||||||
|
|
||||||
// 执行下载与移动操作
|
// 执行下载与移动操作
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
|||||||
|
|
||||||
|
|
||||||
private readonly AppOptions appOptions;
|
private readonly AppOptions appOptions;
|
||||||
private readonly HutaoOptions hutaoOptions;
|
private readonly RuntimeOptions hutaoOptions;
|
||||||
|
|
||||||
private string? localeName;
|
private string? localeName;
|
||||||
private string? fallbackDataFolder;
|
private string? fallbackDataFolder;
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ internal sealed partial class MetadataService
|
|||||||
|
|
||||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
{
|
{
|
||||||
return Must.NotNull((Dictionary<MaterialId, DisplayItem>)value!);
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
return (Dictionary<MaterialId, DisplayItem>)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<MaterialId, DisplayItem> displays = await FromCacheAsDictionaryAsync<MaterialId, DisplayItem>(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false);
|
Dictionary<MaterialId, DisplayItem> displays = await FromCacheAsDictionaryAsync<MaterialId, DisplayItem>(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -167,7 +167,8 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
|
|
||||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
{
|
{
|
||||||
return Must.NotNull((T)value!);
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
return (T)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
string path = metadataOptions.GetLocalizedLocalFile($"{fileName}.json");
|
string path = metadataOptions.GetLocalizedLocalFile($"{fileName}.json");
|
||||||
@@ -176,7 +177,8 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
using (Stream fileStream = File.OpenRead(path))
|
using (Stream fileStream = File.OpenRead(path))
|
||||||
{
|
{
|
||||||
T? result = await JsonSerializer.DeserializeAsync<T>(fileStream, options, token).ConfigureAwait(false);
|
T? result = await JsonSerializer.DeserializeAsync<T>(fileStream, options, token).ConfigureAwait(false);
|
||||||
return memoryCache.Set(cacheKey, Must.NotNull(result!));
|
ArgumentNullException.ThrowIfNull(result);
|
||||||
|
return memoryCache.Set(cacheKey, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -193,11 +195,12 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
|
|
||||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
{
|
{
|
||||||
return Must.NotNull((Dictionary<TKey, TValue>)value!);
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
return (Dictionary<TKey, TValue>)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TValue> list = await FromCacheOrFileAsync<List<TValue>>(fileName, token).ConfigureAwait(false);
|
List<TValue> list = await FromCacheOrFileAsync<List<TValue>>(fileName, token).ConfigureAwait(false);
|
||||||
Dictionary<TKey, TValue> dict = list.ToDictionaryOverride(keySelector);
|
Dictionary<TKey, TValue> dict = list.ToDictionaryIgnoringDuplicateKeys(keySelector); // There are duplicate name items
|
||||||
return memoryCache.Set(cacheKey, dict);
|
return memoryCache.Set(cacheKey, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,11 +211,12 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
|
|
||||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
{
|
{
|
||||||
return Must.NotNull((Dictionary<TKey, TValue>)value!);
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
return (Dictionary<TKey, TValue>)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TData> list = await FromCacheOrFileAsync<List<TData>>(fileName, token).ConfigureAwait(false);
|
List<TData> list = await FromCacheOrFileAsync<List<TData>>(fileName, token).ConfigureAwait(false);
|
||||||
Dictionary<TKey, TValue> dict = list.ToDictionaryOverride(keySelector, valueSelector);
|
Dictionary<TKey, TValue> dict = list.ToDictionaryIgnoringDuplicateKeys(keySelector, valueSelector); // There are duplicate name items
|
||||||
return memoryCache.Set(cacheKey, dict);
|
return memoryCache.Set(cacheKey, dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,8 @@ internal sealed partial class NavigationService : INavigationService, INavigatio
|
|||||||
navigationView.PaneOpened -= OnPaneStateChanged;
|
navigationView.PaneOpened -= OnPaneStateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigationView = Must.NotNull(value!);
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
navigationView = value;
|
||||||
|
|
||||||
// add new listener
|
// add new listener
|
||||||
if (navigationView != null)
|
if (navigationView != null)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ internal sealed partial class CultivateProjectDialog : ContentDialog
|
|||||||
? Ioc.Default.GetRequiredService<IUserService>().Current?.SelectedUserGameRole?.GameUid
|
? Ioc.Default.GetRequiredService<IUserService>().Current?.SelectedUserGameRole?.GameUid
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return new(true, CultivateProject.Create(text, uid));
|
return new(true, CultivateProject.From(text, uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(false, null!);
|
return new(false, null!);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ internal sealed partial class TitleView : UserControl
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Core.HutaoOptions hutaoOptions = Ioc.Default.GetRequiredService<Core.HutaoOptions>();
|
Core.RuntimeOptions hutaoOptions = Ioc.Default.GetRequiredService<Core.RuntimeOptions>();
|
||||||
|
|
||||||
string format =
|
string format =
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
|||||||
|
|
||||||
if (isOk)
|
if (isOk)
|
||||||
{
|
{
|
||||||
ArchiveAddResult result = await achievementService.TryAddArchiveAsync(EntityAchievementArchive.Create(name)).ConfigureAwait(false);
|
ArchiveAddResult result = await achievementService.TryAddArchiveAsync(EntityAchievementArchive.From(name)).ConfigureAwait(false);
|
||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
@@ -230,7 +230,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
|||||||
if (Archives != null && SelectedArchive != null)
|
if (Archives != null && SelectedArchive != null)
|
||||||
{
|
{
|
||||||
ContentDialogResult result = await contentDialogFactory
|
ContentDialogResult result = await contentDialogFactory
|
||||||
.ConfirmCancelAsync(
|
.CreateForConfirmCancelAsync(
|
||||||
string.Format(SH.ViewModelAchievementRemoveArchiveTitle, SelectedArchive.Name),
|
string.Format(SH.ViewModelAchievementRemoveArchiveTitle, SelectedArchive.Name),
|
||||||
SH.ViewModelAchievementRemoveArchiveContent)
|
SH.ViewModelAchievementRemoveArchiveContent)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|||||||
@@ -106,6 +106,6 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableA
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableAvatar(this);
|
return CalculableAvatar.From(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,6 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource<ICalcul
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableSkill ToCalculable()
|
public ICalculableSkill ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableSkill(this);
|
return CalculableSkill.From(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,6 @@ internal sealed class WeaponView : Equip, ICalculableSource<ICalculableWeapon>
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableWeapon ToCalculable()
|
public ICalculableWeapon ToCalculable()
|
||||||
{
|
{
|
||||||
return new CalculableWeapon(this);
|
return CalculableWeapon.From(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,14 +25,14 @@ internal sealed partial class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
[Command("OpenCacheFolderCommand")]
|
[Command("OpenCacheFolderCommand")]
|
||||||
private Task OpenCacheFolderAsync()
|
private Task OpenCacheFolderAsync()
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
return Launcher.LaunchFolderPathAsync(hutaoOptions.LocalCache).AsTask();
|
return Launcher.LaunchFolderPathAsync(hutaoOptions.LocalCache).AsTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("OpenDataFolderCommand")]
|
[Command("OpenDataFolderCommand")]
|
||||||
private Task OpenDataFolderAsync()
|
private Task OpenDataFolderAsync()
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
return Launcher.LaunchFolderPathAsync(hutaoOptions.DataFolder).AsTask();
|
return Launcher.LaunchFolderPathAsync(hutaoOptions.DataFolder).AsTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ internal sealed partial class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
ContentDialogResult result = await scope.ServiceProvider
|
ContentDialogResult result = await scope.ServiceProvider
|
||||||
.GetRequiredService<IContentDialogFactory>()
|
.GetRequiredService<IContentDialogFactory>()
|
||||||
.ConfirmCancelAsync(SH.ViewDialogSettingDeleteUserDataTitle, SH.ViewDialogSettingDeleteUserDataContent)
|
.CreateForConfirmCancelAsync(SH.ViewDialogSettingDeleteUserDataTitle, SH.ViewDialogSettingDeleteUserDataContent)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == ContentDialogResult.Primary)
|
if (result == ContentDialogResult.Primary)
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await contentDialogFactory.ConfirmAsync(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage).ConfigureAwait(false);
|
await contentDialogFactory.CreateForConfirmAsync(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
|||||||
if (Archives != null && SelectedArchive != null)
|
if (Archives != null && SelectedArchive != null)
|
||||||
{
|
{
|
||||||
ContentDialogResult result = await contentDialogFactory
|
ContentDialogResult result = await contentDialogFactory
|
||||||
.ConfirmCancelAsync(string.Format(SH.ViewModelGachaLogRemoveArchiveTitle, SelectedArchive.Uid), SH.ViewModelGachaLogRemoveArchiveDescription)
|
.CreateForConfirmCancelAsync(string.Format(SH.ViewModelGachaLogRemoveArchiveTitle, SelectedArchive.Uid), SH.ViewModelGachaLogRemoveArchiveDescription)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == ContentDialogResult.Primary)
|
if (result == ContentDialogResult.Primary)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly LaunchOptions launchOptions;
|
private readonly LaunchOptions launchOptions;
|
||||||
private readonly HutaoOptions hutaoOptions;
|
private readonly RuntimeOptions hutaoOptions;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly IGameService gameService;
|
private readonly IGameService gameService;
|
||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
@@ -86,7 +86,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 胡桃选项
|
/// 胡桃选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HutaoOptions HutaoOptions { get => hutaoOptions; }
|
public RuntimeOptions HutaoOptions { get => hutaoOptions; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用选项
|
/// 应用选项
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
|||||||
private readonly IGameService gameService;
|
private readonly IGameService gameService;
|
||||||
private readonly ILogger<SettingViewModel> logger;
|
private readonly ILogger<SettingViewModel> logger;
|
||||||
private readonly AppOptions options;
|
private readonly AppOptions options;
|
||||||
private readonly HutaoOptions hutaoOptions;
|
private readonly RuntimeOptions hutaoOptions;
|
||||||
private readonly HutaoUserOptions hutaoUserOptions;
|
private readonly HutaoUserOptions hutaoUserOptions;
|
||||||
private readonly ExperimentalFeaturesViewModel experimental;
|
private readonly ExperimentalFeaturesViewModel experimental;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 胡桃选项
|
/// 胡桃选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HutaoOptions HutaoOptions { get => hutaoOptions; }
|
public RuntimeOptions HutaoOptions { get => hutaoOptions; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 胡桃用户选项
|
/// 胡桃用户选项
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ internal sealed partial class UserViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly IInfoBarService infoBarService;
|
private readonly IInfoBarService infoBarService;
|
||||||
private readonly Core.HutaoOptions hutaoOptions;
|
private readonly Core.RuntimeOptions hutaoOptions;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly IUserService userService;
|
private readonly IUserService userService;
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ internal sealed partial class WelcomeViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
Dictionary<string, DownloadSummary> downloadSummaries = new();
|
Dictionary<string, DownloadSummary> downloadSummaries = new();
|
||||||
|
|
||||||
if (StaticResource.IsContractUnfulfilled(SettingKeys.StaticResourceV1Contract))
|
if (StaticResource.IsContractUnfulfilled(StaticResource.V1Contract))
|
||||||
{
|
{
|
||||||
downloadSummaries.TryAdd("Bg", new(serviceProvider, "Bg"));
|
downloadSummaries.TryAdd("Bg", new(serviceProvider, "Bg"));
|
||||||
downloadSummaries.TryAdd("AvatarIcon", new(serviceProvider, "AvatarIcon"));
|
downloadSummaries.TryAdd("AvatarIcon", new(serviceProvider, "AvatarIcon"));
|
||||||
@@ -83,7 +83,7 @@ internal sealed partial class WelcomeViewModel : ObservableObject
|
|||||||
downloadSummaries.TryAdd("Talent", new(serviceProvider, "Talent"));
|
downloadSummaries.TryAdd("Talent", new(serviceProvider, "Talent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StaticResource.IsContractUnfulfilled(SettingKeys.StaticResourceV2Contract))
|
if (StaticResource.IsContractUnfulfilled(StaticResource.V2Contract))
|
||||||
{
|
{
|
||||||
downloadSummaries.TryAdd("AchievementIcon", new(serviceProvider, "AchievementIcon"));
|
downloadSummaries.TryAdd("AchievementIcon", new(serviceProvider, "AchievementIcon"));
|
||||||
downloadSummaries.TryAdd("ItemIcon", new(serviceProvider, "ItemIcon"));
|
downloadSummaries.TryAdd("ItemIcon", new(serviceProvider, "ItemIcon"));
|
||||||
@@ -91,18 +91,18 @@ internal sealed partial class WelcomeViewModel : ObservableObject
|
|||||||
downloadSummaries.TryAdd("RelicIcon", new(serviceProvider, "RelicIcon"));
|
downloadSummaries.TryAdd("RelicIcon", new(serviceProvider, "RelicIcon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StaticResource.IsContractUnfulfilled(SettingKeys.StaticResourceV3Contract))
|
if (StaticResource.IsContractUnfulfilled(StaticResource.V3Contract))
|
||||||
{
|
{
|
||||||
downloadSummaries.TryAdd("Skill", new(serviceProvider, "Skill"));
|
downloadSummaries.TryAdd("Skill", new(serviceProvider, "Skill"));
|
||||||
downloadSummaries.TryAdd("Talent", new(serviceProvider, "Talent"));
|
downloadSummaries.TryAdd("Talent", new(serviceProvider, "Talent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StaticResource.IsContractUnfulfilled(SettingKeys.StaticResourceV4Contract))
|
if (StaticResource.IsContractUnfulfilled(StaticResource.V4Contract))
|
||||||
{
|
{
|
||||||
downloadSummaries.TryAdd("AvatarIcon", new(serviceProvider, "AvatarIcon"));
|
downloadSummaries.TryAdd("AvatarIcon", new(serviceProvider, "AvatarIcon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StaticResource.IsContractUnfulfilled(SettingKeys.StaticResourceV5Contract))
|
if (StaticResource.IsContractUnfulfilled(StaticResource.V5Contract))
|
||||||
{
|
{
|
||||||
downloadSummaries.TryAdd("MonsterIcon", new(serviceProvider, "MonsterIcon"));
|
downloadSummaries.TryAdd("MonsterIcon", new(serviceProvider, "MonsterIcon"));
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ internal sealed partial class WelcomeViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||||
httpClient = serviceProvider.GetRequiredService<HttpClient>();
|
httpClient = serviceProvider.GetRequiredService<HttpClient>();
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
||||||
|
|
||||||
this.serviceProvider = serviceProvider;
|
this.serviceProvider = serviceProvider;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ internal sealed class HomaLogUploadClient
|
|||||||
|
|
||||||
private static HutaoLog BuildFromException(IServiceProvider serviceProvider, Exception exception)
|
private static HutaoLog BuildFromException(IServiceProvider serviceProvider, Exception exception)
|
||||||
{
|
{
|
||||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user