mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
[skip ci] uigf 4 support part 1
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序资源提供器
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient, typeof(IAppResourceProvider))]
|
||||
internal sealed class AppResourceProvider : IAppResourceProvider
|
||||
{
|
||||
private readonly App app;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的应用程序资源提供器
|
||||
/// </summary>
|
||||
/// <param name="app">应用</param>
|
||||
public AppResourceProvider(App app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T GetResource<T>(string name)
|
||||
{
|
||||
return (T)app.Resources[name];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace Snap.Hutao.Core.Json.Converter;
|
||||
|
||||
internal sealed class DateTimeConverter : JsonConverter<DateTime>
|
||||
{
|
||||
private const string Format = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.GetString() is { } dataTimeString)
|
||||
{
|
||||
return DateTime.ParseExact(dataTimeString, Format, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,14 @@
|
||||
|
||||
namespace Snap.Hutao.Core.Threading.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 <see langword="await"/> 异步等待。
|
||||
/// </summary>
|
||||
/// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter 的实例。</typeparam>
|
||||
internal interface IAwaitable<out TAwaiter>
|
||||
where TAwaiter : IAwaiter
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取一个可用于 await 关键字异步等待的异步等待对象。
|
||||
/// 此方法会被编译器自动调用。
|
||||
/// </summary>
|
||||
/// <returns>等待器</returns>
|
||||
TAwaiter GetAwaiter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个包含返回值的可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 <see langword="await"/> 异步等待返回值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TAwaiter">用于给 await 确定返回时机的 <see cref="IAwaiter{TResult}"/> 的实例。</typeparam>
|
||||
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
|
||||
internal interface IAwaitable<out TAwaiter, out TResult>
|
||||
where TAwaiter : IAwaiter<TResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取一个可用于 await 关键字异步等待的异步等待对象。
|
||||
/// 此方法会被编译器自动调用。
|
||||
/// </summary>
|
||||
/// <returns>等待器</returns>
|
||||
TAwaiter GetAwaiter();
|
||||
}
|
||||
@@ -5,38 +5,16 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// 用于给 await 确定异步返回的时机。
|
||||
/// </summary>
|
||||
internal interface IAwaiter : INotifyCompletion
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
|
||||
/// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
|
||||
/// </summary>
|
||||
bool IsCompleted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 此方法会被编译器在 await 结束时自动调用以获取返回状态(包括异常)。
|
||||
/// </summary>
|
||||
void GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于给 await 确定异步返回的时机,并获取到返回值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
|
||||
internal interface IAwaiter<out TResult> : INotifyCompletion
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
|
||||
/// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
|
||||
/// </summary>
|
||||
bool IsCompleted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取此异步等待操作的返回值,此方法会被编译器在 await 结束时自动调用以获取返回值(包括异常)。
|
||||
/// </summary>
|
||||
/// <returns>异步操作的返回值。</returns>
|
||||
TResult GetResult();
|
||||
}
|
||||
@@ -5,19 +5,10 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
|
||||
/// 用于给 await 确定异步返回的时机。
|
||||
/// </summary>
|
||||
internal interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
|
||||
/// 用于给 await 确定异步返回的时机,并获取到返回值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
|
||||
internal interface ICriticalAwaiter<out TResult> : IAwaiter<TResult>, ICriticalNotifyCompletion
|
||||
{
|
||||
}
|
||||
@@ -18,6 +18,7 @@ internal readonly struct DispatcherQueueSwitchOperation : IAwaitable<DispatcherQ
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
// Only yields when we are not on the DispatcherQueue thread.
|
||||
get => dispatherQueue.HasThreadAccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ internal readonly struct ThreadPoolSwitchOperation : IAwaitable<ThreadPoolSwitch
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
// 如果已经处于后台就不再切换新的线程
|
||||
// Only yields when we are on the DispatcherQueue thread.
|
||||
get => !dispatherQueue.HasThreadAccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序资源提供器
|
||||
/// </summary>
|
||||
internal interface IAppResourceProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取资源
|
||||
/// </summary>
|
||||
/// <typeparam name="T">资源的类型</typeparam>
|
||||
/// <param name="key">资源的名称</param>
|
||||
/// <returns>资源</returns>
|
||||
T GetResource<T>(string key);
|
||||
}
|
||||
@@ -17,8 +17,8 @@ namespace Snap.Hutao.Model.Entity;
|
||||
[Table("gacha_items")]
|
||||
internal sealed partial class GachaItem
|
||||
: IDbMappingForeignKeyFrom<GachaItem, GachaLogItem, uint>,
|
||||
IDbMappingForeignKeyFrom<GachaItem, UIGFItem, uint>,
|
||||
IDbMappingForeignKeyFrom<GachaItem, UIGFItem>,
|
||||
IDbMappingForeignKeyFrom<GachaItem, LegacyUIGFItem, uint>,
|
||||
IDbMappingForeignKeyFrom<GachaItem, LegacyUIGFItem>,
|
||||
IDbMappingForeignKeyFrom<GachaItem, Web.Hutao.GachaLog.GachaItem>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -93,7 +93,7 @@ internal sealed partial class GachaItem
|
||||
/// <param name="item">祈愿物品</param>
|
||||
/// <param name="itemId">物品Id</param>
|
||||
/// <returns>新的祈愿物品</returns>
|
||||
public static GachaItem From(in Guid archiveId, in UIGFItem item, in uint itemId)
|
||||
public static GachaItem From(in Guid archiveId, in LegacyUIGFItem item, in uint itemId)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
@@ -112,7 +112,7 @@ internal sealed partial class GachaItem
|
||||
/// <param name="archiveId">存档Id</param>
|
||||
/// <param name="item">祈愿物品</param>
|
||||
/// <returns>新的祈愿物品</returns>
|
||||
public static GachaItem From(in Guid archiveId, in UIGFItem item)
|
||||
public static GachaItem From(in Guid archiveId, in LegacyUIGFItem item)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
/// https://uigf.org/standards/UIGF.html
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
[Obsolete]
|
||||
internal sealed class LegacyUIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前版本
|
||||
@@ -24,19 +25,19 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
/// </summary>
|
||||
[JsonRequired]
|
||||
[JsonPropertyName("info")]
|
||||
public UIGFInfo Info { get; set; } = default!;
|
||||
public LegacyUIGFInfo Info { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 列表
|
||||
/// </summary>
|
||||
[JsonPropertyName("list")]
|
||||
public List<UIGFItem> List { get; set; } = default!;
|
||||
public List<LegacyUIGFItem> List { get; set; } = default!;
|
||||
|
||||
public void OnSerializing()
|
||||
{
|
||||
TimeSpan offset = GetRegionTimeZoneUtcOffset();
|
||||
|
||||
foreach (UIGFItem item in List)
|
||||
foreach (LegacyUIGFItem item in List)
|
||||
{
|
||||
item.Time = item.Time.ToOffset(offset);
|
||||
}
|
||||
@@ -47,30 +48,30 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
// Adjust items timezone
|
||||
TimeSpan offset = GetRegionTimeZoneUtcOffset();
|
||||
|
||||
foreach (UIGFItem item in List)
|
||||
foreach (LegacyUIGFItem item in List)
|
||||
{
|
||||
item.Time = UnsafeDateTimeOffset.AdjustOffsetOnly(item.Time, offset);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCurrentVersionSupported(out UIGFVersion version)
|
||||
public bool IsCurrentVersionSupported(out LegacyUIGFVersion version)
|
||||
{
|
||||
version = Info.UIGFVersion switch
|
||||
{
|
||||
"v2.1" => UIGFVersion.Major2Minor2OrLower,
|
||||
"v2.2" => UIGFVersion.Major2Minor2OrLower,
|
||||
"v2.3" => UIGFVersion.Major2Minor3OrHigher,
|
||||
"v2.4" => UIGFVersion.Major2Minor3OrHigher,
|
||||
"v3.0" => UIGFVersion.Major2Minor3OrHigher,
|
||||
_ => UIGFVersion.NotSupported,
|
||||
"v2.1" => LegacyUIGFVersion.Major2Minor2OrLower,
|
||||
"v2.2" => LegacyUIGFVersion.Major2Minor2OrLower,
|
||||
"v2.3" => LegacyUIGFVersion.Major2Minor3OrHigher,
|
||||
"v2.4" => LegacyUIGFVersion.Major2Minor3OrHigher,
|
||||
"v3.0" => LegacyUIGFVersion.Major2Minor3OrHigher,
|
||||
_ => LegacyUIGFVersion.NotSupported,
|
||||
};
|
||||
|
||||
return version != UIGFVersion.NotSupported;
|
||||
return version != LegacyUIGFVersion.NotSupported;
|
||||
}
|
||||
|
||||
public bool IsMajor2Minor2OrLowerListValid([NotNullWhen(false)] out long id)
|
||||
{
|
||||
foreach (ref readonly UIGFItem item in CollectionsMarshal.AsSpan(List))
|
||||
foreach (ref readonly LegacyUIGFItem item in CollectionsMarshal.AsSpan(List))
|
||||
{
|
||||
if (item.ItemType != SH.ModelInterchangeUIGFItemTypeAvatar && item.ItemType != SH.ModelInterchangeUIGFItemTypeWeapon)
|
||||
{
|
||||
@@ -85,7 +86,7 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
|
||||
public bool IsMajor2Minor3OrHigherListValid([NotNullWhen(false)] out long id)
|
||||
{
|
||||
foreach (ref readonly UIGFItem item in CollectionsMarshal.AsSpan(List))
|
||||
foreach (ref readonly LegacyUIGFItem item in CollectionsMarshal.AsSpan(List))
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.ItemId))
|
||||
{
|
||||
@@ -12,7 +12,8 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
/// UIGF格式的信息
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, CultureOptions, string>
|
||||
[Obsolete]
|
||||
internal sealed class LegacyUIGFInfo : IMappingFrom<LegacyUIGFInfo, RuntimeOptions, CultureOptions, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Uid
|
||||
@@ -65,7 +66,7 @@ internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, CultureO
|
||||
[JsonPropertyName("region_time_zone")]
|
||||
public int? RegionTimeZone { get; set; } = default!;
|
||||
|
||||
public static UIGFInfo From(RuntimeOptions runtimeOptions, CultureOptions cultureOptions, string uid)
|
||||
public static LegacyUIGFInfo From(RuntimeOptions runtimeOptions, CultureOptions cultureOptions, string uid)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
@@ -74,7 +75,7 @@ internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, CultureO
|
||||
ExportTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
||||
ExportApp = SH.AppName,
|
||||
ExportAppVersion = runtimeOptions.Version.ToString(),
|
||||
UIGFVersion = UIGF.CurrentVersion,
|
||||
UIGFVersion = LegacyUIGF.CurrentVersion,
|
||||
RegionTimeZone = PlayerUid.GetRegionTimeZoneUtcOffsetForUid(uid).Hours,
|
||||
};
|
||||
}
|
||||
@@ -13,7 +13,8 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
/// UIGF物品
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class UIGFItem : GachaLogItem, IMappingFrom<UIGFItem, GachaItem, INameQualityAccess>
|
||||
[Obsolete]
|
||||
internal sealed class LegacyUIGFItem : GachaLogItem, IMappingFrom<LegacyUIGFItem, GachaItem, INameQualityAccess>
|
||||
{
|
||||
/// <summary>
|
||||
/// 额外祈愿映射
|
||||
@@ -22,7 +23,7 @@ internal sealed class UIGFItem : GachaLogItem, IMappingFrom<UIGFItem, GachaItem,
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public GachaType UIGFGachaType { get; set; } = default!;
|
||||
|
||||
public static UIGFItem From(GachaItem item, INameQualityAccess nameQuality)
|
||||
public static LegacyUIGFItem From(GachaItem item, INameQualityAccess nameQuality)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
@@ -32,7 +33,7 @@ internal sealed class UIGFItem : GachaLogItem, IMappingFrom<UIGFItem, GachaItem,
|
||||
Time = item.Time,
|
||||
Name = nameQuality.Name,
|
||||
ItemType = GetItemTypeStringByItemId(item.ItemId),
|
||||
Rank = nameQuality.Quality,
|
||||
RankType = nameQuality.Quality,
|
||||
Id = item.Id,
|
||||
UIGFGachaType = item.QueryType,
|
||||
};
|
||||
@@ -6,7 +6,8 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
/// <summary>
|
||||
/// UIGF版本
|
||||
/// </summary>
|
||||
internal enum UIGFVersion
|
||||
[Obsolete]
|
||||
internal enum LegacyUIGFVersion
|
||||
{
|
||||
/// <summary>
|
||||
/// 不支持的版本
|
||||
43
src/Snap.Hutao/Snap.Hutao/Model/InterChange/Hk4eItem.cs
Normal file
43
src/Snap.Hutao/Snap.Hutao/Model/InterChange/Hk4eItem.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Core.Json.Annotation;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange;
|
||||
|
||||
internal sealed class Hk4eItem : IMappingFrom<Hk4eItem, GachaItem>
|
||||
{
|
||||
[JsonPropertyName("uigf_gacha_type")]
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public required GachaType UIGFGachaType { get; set; }
|
||||
|
||||
[JsonPropertyName("gacha_type")]
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public required GachaType GachaType { get; set; }
|
||||
|
||||
[JsonPropertyName("item_id")]
|
||||
public required uint ItemId { get; set; }
|
||||
|
||||
[JsonPropertyName("time")]
|
||||
[JsonConverter(typeof(Core.Json.Converter.DateTimeConverter))]
|
||||
public required DateTime Time { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
public required long Id { get; set; } = default!;
|
||||
|
||||
public static Hk4eItem From(GachaItem item)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
UIGFGachaType = item.QueryType,
|
||||
GachaType = item.GachaType,
|
||||
ItemId = item.ItemId,
|
||||
Time = item.Time.UtcDateTime,
|
||||
Id = item.Id,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange;
|
||||
|
||||
internal sealed class HutaoReserved
|
||||
{
|
||||
public required uint Version { get; set; }
|
||||
}
|
||||
16
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGF.cs
Normal file
16
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGF.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange;
|
||||
|
||||
internal sealed class UIGF
|
||||
{
|
||||
[JsonPropertyName("info")]
|
||||
public required UIGFInfo Info { get; set; }
|
||||
|
||||
[JsonPropertyName("hk4e")]
|
||||
public List<UIGFEntry<Hk4eItem>>? Hk4e { get; set; }
|
||||
|
||||
[JsonPropertyName("snap_hutao_reserved")]
|
||||
public HutaoReserved? HutaoReserved { get; set; }
|
||||
}
|
||||
19
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFEntry.cs
Normal file
19
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFEntry.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange;
|
||||
|
||||
internal sealed class UIGFEntry<TItem>
|
||||
{
|
||||
[JsonPropertyName("uid")]
|
||||
public required string Uid { get; set; }
|
||||
|
||||
[JsonPropertyName("timezone")]
|
||||
public required int TimeZone { get; set; }
|
||||
|
||||
[JsonPropertyName("lang")]
|
||||
public string? Language { get; set; }
|
||||
|
||||
[JsonPropertyName("list")]
|
||||
public required List<TItem> List { get; set; }
|
||||
}
|
||||
19
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFInfo.cs
Normal file
19
src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange;
|
||||
|
||||
internal sealed class UIGFInfo
|
||||
{
|
||||
[JsonPropertyName("export_timestamp")]
|
||||
public required long ExportTimestamp { get; set; }
|
||||
|
||||
[JsonPropertyName("export_app")]
|
||||
public required string ExportApp { get; set; }
|
||||
|
||||
[JsonPropertyName("export_app_version")]
|
||||
public required string ExportAppVersion { get; set; }
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public required string Version { get; set; }
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Model.InterChange;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -85,12 +85,12 @@ internal sealed partial class GachaLogService : IGachaLogService
|
||||
return statistics;
|
||||
}
|
||||
|
||||
public ValueTask<UIGF> ExportToUIGFAsync(GachaArchive archive)
|
||||
public ValueTask<LegacyUIGF> ExportToUIGFAsync(GachaArchive archive)
|
||||
{
|
||||
return gachaLogExportService.ExportAsync(context, archive);
|
||||
}
|
||||
|
||||
public async ValueTask ImportFromUIGFAsync(UIGF uigf)
|
||||
public async ValueTask ImportFromUIGFAsync(LegacyUIGF uigf)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(Archives);
|
||||
await gachaLogImportService.ImportAsync(context, uigf, Archives).ConfigureAwait(false);
|
||||
|
||||
@@ -24,7 +24,7 @@ internal interface IGachaLogService
|
||||
/// </summary>
|
||||
/// <param name="archive">存档</param>
|
||||
/// <returns>UIGF对象</returns>
|
||||
ValueTask<UIGF> ExportToUIGFAsync(GachaArchive archive);
|
||||
ValueTask<LegacyUIGF> ExportToUIGFAsync(GachaArchive archive);
|
||||
|
||||
/// <summary>
|
||||
/// 获得对应的祈愿统计
|
||||
@@ -45,7 +45,7 @@ internal interface IGachaLogService
|
||||
/// </summary>
|
||||
/// <param name="uigf">信息</param>
|
||||
/// <returns>任务</returns>
|
||||
ValueTask ImportFromUIGFAsync(UIGF uigf);
|
||||
ValueTask ImportFromUIGFAsync(LegacyUIGF uigf);
|
||||
|
||||
/// <summary>
|
||||
/// 异步初始化
|
||||
|
||||
@@ -17,5 +17,5 @@ internal interface IUIGFExportService
|
||||
/// <param name="context">元数据上下文</param>
|
||||
/// <param name="archive">存档</param>
|
||||
/// <returns>UIGF</returns>
|
||||
ValueTask<UIGF> ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive);
|
||||
ValueTask<LegacyUIGF> ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive);
|
||||
}
|
||||
|
||||
@@ -12,5 +12,5 @@ namespace Snap.Hutao.Service.GachaLog;
|
||||
/// </summary>
|
||||
internal interface IUIGFImportService
|
||||
{
|
||||
ValueTask ImportAsync(GachaLogServiceMetadataContext context, UIGF uigf, AdvancedDbCollectionView<GachaArchive> archives);
|
||||
ValueTask ImportAsync(GachaLogServiceMetadataContext context, LegacyUIGF uigf, AdvancedDbCollectionView<GachaArchive> archives);
|
||||
}
|
||||
@@ -20,15 +20,15 @@ internal sealed partial class UIGFExportService : IUIGFExportService
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<UIGF> ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive)
|
||||
public async ValueTask<LegacyUIGF> ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
List<GachaItem> entities = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId);
|
||||
List<UIGFItem> list = entities.SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId)));
|
||||
List<LegacyUIGFItem> list = entities.SelectList(i => LegacyUIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId)));
|
||||
|
||||
UIGF uigf = new()
|
||||
LegacyUIGF uigf = new()
|
||||
{
|
||||
Info = UIGFInfo.From(runtimeOptions, cultureOptions, archive.Uid),
|
||||
Info = LegacyUIGFInfo.From(runtimeOptions, cultureOptions, archive.Uid),
|
||||
List = list,
|
||||
};
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
private readonly CultureOptions cultureOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public async ValueTask ImportAsync(GachaLogServiceMetadataContext context, UIGF uigf, AdvancedDbCollectionView<GachaArchive> archives)
|
||||
public async ValueTask ImportAsync(GachaLogServiceMetadataContext context, LegacyUIGF uigf, AdvancedDbCollectionView<GachaArchive> archives)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
if (!uigf.IsCurrentVersionSupported(out UIGFVersion version))
|
||||
if (!uigf.IsCurrentVersionSupported(out LegacyUIGFVersion version))
|
||||
{
|
||||
HutaoException.InvalidOperation(SH.ServiceUIGFImportUnsupportedVersion);
|
||||
}
|
||||
@@ -30,7 +30,7 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
// v2.3+ supports any locale
|
||||
// v2.2 only supports matched locale
|
||||
// v2.1 only supports CHS
|
||||
if (version is UIGFVersion.Major2Minor2OrLower)
|
||||
if (version is LegacyUIGFVersion.Major2Minor2OrLower)
|
||||
{
|
||||
if (!cultureOptions.LanguageCodeFitsCurrentLocale(uigf.Info.Language))
|
||||
{
|
||||
@@ -45,7 +45,7 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
}
|
||||
}
|
||||
|
||||
if (version is UIGFVersion.Major2Minor3OrHigher)
|
||||
if (version is LegacyUIGFVersion.Major2Minor3OrHigher)
|
||||
{
|
||||
if (!uigf.IsMajor2Minor3OrHigherListValid(out long id))
|
||||
{
|
||||
@@ -65,12 +65,12 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
|
||||
List<GachaItem> currentTypedList = version switch
|
||||
{
|
||||
UIGFVersion.Major2Minor3OrHigher => uigf.List
|
||||
LegacyUIGFVersion.Major2Minor3OrHigher => uigf.List
|
||||
.Where(item => item.UIGFGachaType == queryType && item.Id < trimId)
|
||||
.OrderByDescending(item => item.Id)
|
||||
.Select(item => GachaItem.From(archiveId, item))
|
||||
.ToList(),
|
||||
UIGFVersion.Major2Minor2OrLower => uigf.List
|
||||
LegacyUIGFVersion.Major2Minor2OrLower => uigf.List
|
||||
.Where(item => item.UIGFGachaType == queryType && item.Id < trimId)
|
||||
.OrderByDescending(item => item.Id)
|
||||
.Select(item => GachaItem.From(archiveId, item, context.GetItemId(item)))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
internal interface IUIGFExportService
|
||||
{
|
||||
ValueTask<bool> ExportAsync(UIGFExportOptions exportOptions, CancellationToken token);
|
||||
}
|
||||
9
src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs
Normal file
9
src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
internal interface IUIGFService
|
||||
{
|
||||
ValueTask<bool> ExportAsync(UIGFExportOptions exportOptions, CancellationToken token);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange;
|
||||
using Snap.Hutao.Service.GachaLog;
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Transient, typeof(IUIGFExportService), Key = UIGFVersion.UIGF40)]
|
||||
internal sealed partial class UIGF40ExportService : IUIGFExportService
|
||||
{
|
||||
private readonly IGachaLogDbService gachaLogDbService;
|
||||
private readonly JsonSerializerOptions jsonOptions;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public async ValueTask<bool> ExportAsync(UIGFExportOptions exportOptions, CancellationToken token)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
Model.InterChange.UIGF uigf = new()
|
||||
{
|
||||
Info = new()
|
||||
{
|
||||
ExportApp = "Snap Hutao",
|
||||
ExportAppVersion = $"{runtimeOptions.Version}",
|
||||
ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(),
|
||||
Version = "v4.0",
|
||||
},
|
||||
HutaoReserved = new()
|
||||
{
|
||||
Version = 1,
|
||||
},
|
||||
};
|
||||
|
||||
ExportGachaArchives(uigf, exportOptions.GachaArchiveIds);
|
||||
|
||||
using (FileStream stream = File.Create(exportOptions.FilePath))
|
||||
{
|
||||
await JsonSerializer.SerializeAsync(stream, uigf, jsonOptions, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ExportGachaArchives(Model.InterChange.UIGF uigf, List<Guid> archiveIds)
|
||||
{
|
||||
List<UIGFEntry<Hk4eItem>> hk4eEntries = [];
|
||||
foreach (Guid archiveId in archiveIds)
|
||||
{
|
||||
GachaArchive? archive = gachaLogDbService.GetGachaArchiveById(archiveId);
|
||||
ArgumentNullException.ThrowIfNull(archive);
|
||||
List<GachaItem> dbItems = gachaLogDbService.GetGachaItemListByArchiveId(archiveId);
|
||||
UIGFEntry<Hk4eItem> entry = new()
|
||||
{
|
||||
Uid = archive.Uid,
|
||||
TimeZone = 0,
|
||||
List = [.. dbItems.Select(Hk4eItem.From)],
|
||||
};
|
||||
|
||||
hk4eEntries.Add(entry);
|
||||
}
|
||||
|
||||
uigf.Hk4e = hk4eEntries;
|
||||
}
|
||||
}
|
||||
21
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs
Normal file
21
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
internal sealed class UIGFExportOptions
|
||||
{
|
||||
public string FilePath { get; set; } = default!;
|
||||
|
||||
public List<Guid> GachaArchiveIds { get; set; } = [];
|
||||
|
||||
public List<Guid> ReservedAchievementArchiveIds { get; set; } = [];
|
||||
|
||||
public List<string> ReservedAvatarInfoUids { get; set; } = [];
|
||||
|
||||
public List<Guid> ReservedCultivationProjectIds { get; set; } = [];
|
||||
|
||||
public List<string> ReservedSpiralAbyssUids { get; set; } = [];
|
||||
|
||||
public List<Guid> ReservedUserIds { get; set; } = [];
|
||||
}
|
||||
17
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs
Normal file
17
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Transient, typeof(IUIGFService))]
|
||||
internal sealed partial class UIGFService : IUIGFService
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public ValueTask<bool> ExportAsync(UIGFExportOptions exportOptions, CancellationToken token)
|
||||
{
|
||||
IUIGFExportService exportService = serviceProvider.GetRequiredKeyedService<IUIGFExportService>(UIGFVersion.UIGF40);
|
||||
return exportService.ExportAsync(exportOptions, token);
|
||||
}
|
||||
}
|
||||
10
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFVersion.cs
Normal file
10
src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFVersion.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.UIGF;
|
||||
|
||||
internal enum UIGFVersion
|
||||
{
|
||||
None,
|
||||
UIGF40,
|
||||
}
|
||||
@@ -158,7 +158,6 @@
|
||||
<None Remove="UI\Xaml\View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\DailyNoteWebhookDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\GachaLogImportDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\GachaLogRefreshProgressDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\GachaLogUrlDialog.xaml" />
|
||||
<None Remove="UI\Xaml\View\Dialog\GeetestCustomUrlDialog.xaml" />
|
||||
|
||||
@@ -697,7 +697,8 @@ internal sealed partial class AutoSuggestTokenBox : ListViewBase
|
||||
// This code is only fires during an edgecase where an item is in the process of being deleted and the user inputs a character before the focus has been redirected to a string container.
|
||||
if (innerItemsSource[^1] is ITokenStringContainer textEdit)
|
||||
{
|
||||
if (ContainerFromIndex(Items.Count - 1) is AutoSuggestTokenBoxItem last) // Should be our last text box
|
||||
// Should be our last text box
|
||||
if (ContainerFromIndex(Items.Count - 1) is AutoSuggestTokenBoxItem last)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(last.AutoSuggestTextBox);
|
||||
string text = last.AutoSuggestTextBox.Text;
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace Snap.Hutao.UI.Xaml.Markup;
|
||||
[MarkupExtensionReturnType(ReturnType = typeof(string))]
|
||||
internal sealed class ResourceStringExtension : MarkupExtension
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
private string? name;
|
||||
|
||||
public string? Name { get => name; set => name = value is null ? null : string.Intern(value); }
|
||||
|
||||
public string? CultureName { get; set; }
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.UI.Xaml.View.Dialog.GachaLogImportDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shuxm="using:Snap.Hutao.UI.Xaml.Markup"
|
||||
Title="{shuxm:ResourceString Name=ViewDialogGachaLogImportTitle}"
|
||||
CloseButtonText="{shuxm:ResourceString Name=ContentDialogCancelCloseButtonText}"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="{shuxm:ResourceString Name=ContentDialogConfirmPrimaryButtonText}"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<cwc:UniformGrid
|
||||
Grid.Row="0"
|
||||
ColumnSpacing="16"
|
||||
Columns="3"
|
||||
RowSpacing="16">
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportExportApp}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.Info.ExportApp, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportExportTime}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.Info.ExportDateTime.LocalDateTime, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportExportAppVersion}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.Info.ExportAppVersion, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportUIGFExportUIGFVersion}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.Info.UIGFVersion, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportUIGFExportListCount}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.List.Count, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
<cwc:HeaderedContentControl Header="{shuxm:ResourceString Name=ViewDialogImportUIGFExportUid}">
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind UIGF.Info.Uid, Mode=OneWay, TargetNullValue=未知}"/>
|
||||
</cwc:HeaderedContentControl>
|
||||
</cwc:UniformGrid>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿记录导入对话框
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[DependencyProperty("UIGF", typeof(UIGF))]
|
||||
internal sealed partial class GachaLogImportDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的祈愿记录导入对话框
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="uigf">uigf数据</param>
|
||||
public GachaLogImportDialog(IServiceProvider serviceProvider, UIGF uigf)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
UIGF = uigf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取导入选项
|
||||
/// </summary>
|
||||
/// <returns>是否导入</returns>
|
||||
public async ValueTask<bool> GetShouldImportAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
return await ShowAsync() == ContentDialogResult.Primary;
|
||||
}
|
||||
}
|
||||
@@ -317,4 +317,4 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
infoBarService.Warning(SH.ViewModelAvatatPropertyExportTextError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,8 +241,8 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
ValueResult<bool, UIGF?> result = await file.DeserializeFromJsonAsync<UIGF>(options).ConfigureAwait(false);
|
||||
if (result.TryGetValue(out UIGF? uigf))
|
||||
ValueResult<bool, LegacyUIGF?> result = await file.DeserializeFromJsonAsync<LegacyUIGF>(options).ConfigureAwait(false);
|
||||
if (result.TryGetValue(out LegacyUIGF? uigf))
|
||||
{
|
||||
await TryImportUIGFInternalAsync(uigf).ConfigureAwait(false);
|
||||
}
|
||||
@@ -270,7 +270,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
UIGF uigf = await gachaLogService.ExportToUIGFAsync(Archives.CurrentItem).ConfigureAwait(false);
|
||||
LegacyUIGF uigf = await gachaLogService.ExportToUIGFAsync(Archives.CurrentItem).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uigf, options).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelExportSuccessTitle, SH.ViewModelExportSuccessMessage);
|
||||
@@ -348,7 +348,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> TryImportUIGFInternalAsync(UIGF uigf)
|
||||
private async ValueTask<bool> TryImportUIGFInternalAsync(LegacyUIGF uigf)
|
||||
{
|
||||
if (!uigf.IsCurrentVersionSupported(out _))
|
||||
{
|
||||
|
||||
@@ -12,68 +12,37 @@ namespace Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
[HighQuality]
|
||||
internal class GachaLogItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 玩家Uid
|
||||
/// </summary>
|
||||
[JsonPropertyName("uid")]
|
||||
public string Uid { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿类型
|
||||
/// </summary>
|
||||
[JsonPropertyName("gacha_type")]
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public GachaType GachaType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 总为 <see cref="string.Empty"/>
|
||||
/// v2.3 使用了此值
|
||||
/// </summary>
|
||||
[JsonPropertyName("item_id")]
|
||||
public string ItemId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 个数 一般为 1
|
||||
/// </summary>
|
||||
[JsonPropertyName("count")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
public int? Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
[JsonPropertyName("time")]
|
||||
[JsonConverter(typeof(Core.Json.Converter.DateTimeOffsetConverter))]
|
||||
public DateTimeOffset Time { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
[JsonPropertyName("lang")]
|
||||
public string Language { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
/// </summary>
|
||||
[JsonPropertyName("item_type")]
|
||||
public string ItemType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品稀有等级
|
||||
/// </summary>
|
||||
[JsonPropertyName("rank_type")]
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public QualityType Rank { get; set; } = default!;
|
||||
public QualityType RankType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
public long Id { get; set; } = default!;
|
||||
|
||||
Reference in New Issue
Block a user