diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFileExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFileExtension.cs index c2f393c1..63496f07 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFileExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/ValueFileExtension.cs @@ -18,9 +18,8 @@ internal static class ValueFileExtension return new(true, t); } } - catch (Exception ex) + catch (Exception) { - _ = ex; return new(false, null); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs index 2543cad3..542ac726 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs @@ -15,8 +15,7 @@ namespace Snap.Hutao.Model.Entity; internal sealed class Achievement : IAppDbEntityHasArchive, IEquatable, IDbMappingForeignKeyFrom, - IDbMappingForeignKeyFrom, - IDbMappingForeignKeyFrom + IDbMappingForeignKeyFrom { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -58,18 +57,6 @@ internal sealed class Achievement : IAppDbEntityHasArchive, }; } - public static Achievement From(Guid archiveId, HutaoReservedAchievement achievement) - { - return new() - { - ArchiveId = archiveId, - Id = achievement.Id, - Current = achievement.Current, - Status = achievement.Status, - Time = achievement.Time, - }; - } - public bool Equals(Achievement? other) { if (other is null) diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs index 87db775a..60a0fff1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs @@ -27,7 +27,7 @@ internal sealed class CultivateEntry : IAppDbEntity, public uint Id { get; set; } - public static CultivateEntry From(in Guid projectId, in CultivateType type, in uint id) + public static CultivateEntry From(Guid projectId, CultivateType type, uint id) { return new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateItem.cs index 702ed58c..6415ecc2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateItem.cs @@ -25,7 +25,7 @@ internal sealed class CultivateItem : IDbMappingForeignKeyFrom, - IDbMappingForeignKeyFrom, - IDbMappingForeignKeyFrom, IDbMappingForeignKeyFrom, IDbMappingForeignKeyFrom { @@ -51,32 +48,6 @@ internal sealed partial class GachaItem }; } - public static GachaItem From(Guid archiveId, LegacyUIGFItem item, uint itemId) - { - return new() - { - ArchiveId = archiveId, - GachaType = item.GachaType, - QueryType = item.UIGFGachaType, - ItemId = itemId, - Time = item.Time, - Id = item.Id, - }; - } - - public static GachaItem From(Guid archiveId, LegacyUIGFItem item) - { - return new() - { - ArchiveId = archiveId, - GachaType = item.GachaType, - QueryType = item.UIGFGachaType, - ItemId = uint.Parse(item.ItemId, CultureInfo.CurrentCulture), - Time = item.Time, - Id = item.Id, - }; - } - public static GachaItem From(Guid archiveId, Web.Hutao.GachaLog.GachaItem item) { return new() diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs index 73136219..bff3234a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs @@ -15,41 +15,20 @@ namespace Snap.Hutao.Model.Entity; internal sealed class InventoryItem : IDbMappingForeignKeyFrom, IDbMappingForeignKeyFrom { - /// - /// 内部Id - /// [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid InnerId { get; set; } - /// - /// 培养计划Id - /// public Guid ProjectId { get; set; } - /// - /// 所属的计划 - /// [ForeignKey(nameof(ProjectId))] public CultivateProject Project { get; set; } = default!; - /// - /// 物品Id - /// public uint ItemId { get; set; } - /// - /// 个数 4294967295 - /// public uint Count { get; set; } - /// - /// 构造一个新的个数为0的物品 - /// - /// 项目Id - /// 物品Id - /// 新的个数为0的物品 - public static InventoryItem From(in Guid projectId, in uint itemId) + public static InventoryItem From(Guid projectId, uint itemId) { return new() { @@ -58,14 +37,7 @@ internal sealed class InventoryItem : IDbMappingForeignKeyFrom - /// 构造一个新的个数不为0的物品 - /// - /// 项目Id - /// 物品Id - /// 物品个数 - /// 新的个数不为0的物品 - public static InventoryItem From(in Guid projectId, in uint itemId, in uint count) + public static InventoryItem From(Guid projectId, uint itemId, uint count) { return new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Hk4eItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/Hk4eItem.cs similarity index 96% rename from src/Snap.Hutao/Snap.Hutao/Model/InterChange/Hk4eItem.cs rename to src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/Hk4eItem.cs index 78c8d806..f1cb0bce 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Hk4eItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/Hk4eItem.cs @@ -6,7 +6,7 @@ using Snap.Hutao.Core.Json.Annotation; using Snap.Hutao.Model.Entity; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; -namespace Snap.Hutao.Model.InterChange; +namespace Snap.Hutao.Model.InterChange.GachaLog; internal sealed class Hk4eItem : IMappingFrom { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGF.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGF.cs deleted file mode 100644 index c6354201..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGF.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core; -using Snap.Hutao.Web.Hoyolab; -using System.Runtime.InteropServices; - -namespace Snap.Hutao.Model.InterChange.GachaLog; - -/// -/// 统一可交换祈愿格式 -/// https://uigf.org/standards/UIGF.html -/// -[HighQuality] -[Obsolete] -internal sealed class LegacyUIGF : IJsonOnSerializing, IJsonOnDeserialized -{ - /// - /// 当前版本 - /// - public const string CurrentVersion = "v3.0"; - - /// - /// 信息 - /// - [JsonRequired] - [JsonPropertyName("info")] - public LegacyUIGFInfo Info { get; set; } = default!; - - /// - /// 列表 - /// - [JsonPropertyName("list")] - public List List { get; set; } = default!; - - public void OnSerializing() - { - TimeSpan offset = GetRegionTimeZoneUtcOffset(); - - foreach (LegacyUIGFItem item in List) - { - item.Time = item.Time.ToOffset(offset); - } - } - - public void OnDeserialized() - { - // Adjust items timezone - TimeSpan offset = GetRegionTimeZoneUtcOffset(); - - foreach (LegacyUIGFItem item in List) - { - item.Time = UnsafeDateTimeOffset.AdjustOffsetOnly(item.Time, offset); - } - } - - public bool IsCurrentVersionSupported(out LegacyUIGFVersion version) - { - version = Info.UIGFVersion switch - { - "v2.1" => LegacyUIGFVersion.Major2Minor2OrLower, - "v2.2" => LegacyUIGFVersion.Major2Minor2OrLower, - "v2.3" => LegacyUIGFVersion.Major2Minor3OrHigher, - "v2.4" => LegacyUIGFVersion.Major2Minor3OrHigher, - "v3.0" => LegacyUIGFVersion.Major2Minor3OrHigher, - _ => LegacyUIGFVersion.NotSupported, - }; - - return version != LegacyUIGFVersion.NotSupported; - } - - public bool IsMajor2Minor2OrLowerListValid([NotNullWhen(false)] out long id) - { - foreach (ref readonly LegacyUIGFItem item in CollectionsMarshal.AsSpan(List)) - { - if (item.ItemType != SH.ModelInterchangeUIGFItemTypeAvatar && item.ItemType != SH.ModelInterchangeUIGFItemTypeWeapon) - { - id = item.Id; - return false; - } - } - - id = 0; - return true; - } - - public bool IsMajor2Minor3OrHigherListValid([NotNullWhen(false)] out long id) - { - foreach (ref readonly LegacyUIGFItem item in CollectionsMarshal.AsSpan(List)) - { - if (string.IsNullOrEmpty(item.ItemId)) - { - id = item.Id; - return false; - } - } - - id = 0; - return true; - } - - private TimeSpan GetRegionTimeZoneUtcOffset() - { - if (Info.RegionTimeZone is int offsetHours) - { - return new TimeSpan(offsetHours, 0, 0); - } - - return PlayerUid.GetRegionTimeZoneUtcOffsetForUid(Info.Uid); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFInfo.cs deleted file mode 100644 index d69c1225..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFInfo.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core; -using Snap.Hutao.Core.Abstraction; -using Snap.Hutao.Service; -using Snap.Hutao.Web.Hoyolab; - -namespace Snap.Hutao.Model.InterChange.GachaLog; - -/// -/// UIGF格式的信息 -/// -[HighQuality] -[Obsolete] -internal sealed class LegacyUIGFInfo : IMappingFrom -{ - /// - /// 用户Uid - /// - [JsonPropertyName("uid")] - public string Uid { get; set; } = default!; - - /// - /// 语言 - /// - [JsonPropertyName("lang")] - public string Language { get; set; } = default!; - - /// - /// 导出的时间戳 - /// - [JsonPropertyName("export_timestamp")] - public long? ExportTimestamp { get; set; } - - /// - /// 导出时间 - /// - [JsonIgnore] - public DateTimeOffset ExportDateTime - { - get => DateTimeOffsetExtension.UnsafeRelaxedFromUnixTime(ExportTimestamp, DateTimeOffset.MinValue); - } - - /// - /// 导出的 App 名称 - /// - [JsonPropertyName("export_app")] - public string ExportApp { get; set; } = default!; - - /// - /// 导出的 App 版本 - /// - [JsonPropertyName("export_app_version")] - public string ExportAppVersion { get; set; } = default!; - - /// - /// 使用的UIGF版本 - /// - [JsonPropertyName("uigf_version")] - public string UIGFVersion { get; set; } = default!; - - /// - /// 时区偏移 - /// - [JsonPropertyName("region_time_zone")] - public int? RegionTimeZone { get; set; } = default!; - - public static LegacyUIGFInfo From(RuntimeOptions runtimeOptions, CultureOptions cultureOptions, string uid) - { - return new() - { - Uid = uid, - Language = cultureOptions.LanguageCode, - ExportTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), - ExportApp = SH.AppName, - ExportAppVersion = runtimeOptions.Version.ToString(), - UIGFVersion = LegacyUIGF.CurrentVersion, - RegionTimeZone = PlayerUid.GetRegionTimeZoneUtcOffsetForUid(uid).Hours, - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFItem.cs deleted file mode 100644 index 00fdfeba..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFItem.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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.Model.Metadata.Abstraction; -using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; - -namespace Snap.Hutao.Model.InterChange.GachaLog; - -/// -/// UIGF物品 -/// -[HighQuality] -[Obsolete] -internal sealed class LegacyUIGFItem : GachaLogItem, IMappingFrom -{ - /// - /// 额外祈愿映射 - /// - [JsonPropertyName("uigf_gacha_type")] - [JsonEnum(JsonSerializeType.NumberString)] - public GachaType UIGFGachaType { get; set; } = default!; - - public static LegacyUIGFItem From(GachaItem item, INameQualityAccess nameQuality) - { - return new() - { - GachaType = item.GachaType, - ItemId = $"{item.ItemId:D}", - Count = 1, - Time = item.Time, - Name = nameQuality.Name, - ItemType = GetItemTypeStringByItemId(item.ItemId), - RankType = nameQuality.Quality, - Id = item.Id, - UIGFGachaType = item.QueryType, - }; - } - - private static string GetItemTypeStringByItemId(uint itemId) - { - return itemId.StringLength() switch - { - 8U => SH.ModelInterchangeUIGFItemTypeAvatar, - 5U => SH.ModelInterchangeUIGFItemTypeWeapon, - _ => SH.ModelInterchangeUIGFItemTypeUnknown, - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFVersion.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFVersion.cs deleted file mode 100644 index 91ddf647..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/LegacyUIGFVersion.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Model.InterChange.GachaLog; - -/// -/// UIGF版本 -/// -[Obsolete] -internal enum LegacyUIGFVersion -{ - /// - /// 不支持的版本 - /// - NotSupported, - - /// - /// v2.2以及之前的版本 - /// - Major2Minor2OrLower, - - /// - /// v2.3以及之后的版本 - /// - Major2Minor3OrHigher, -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGF.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs similarity index 67% rename from src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGF.cs rename to src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs index ef903788..a4b0ad2c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGF.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Model.InterChange; +namespace Snap.Hutao.Model.InterChange.GachaLog; internal sealed class UIGF { @@ -10,7 +10,4 @@ internal sealed class UIGF [JsonPropertyName("hk4e")] public List>? Hk4e { get; set; } - - [JsonPropertyName("snap_hutao_reserved")] - public HutaoReserved? HutaoReserved { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFEntry.cs similarity index 80% rename from src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFEntry.cs rename to src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFEntry.cs index d6a8f57e..e38326d3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFEntry.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Model.InterChange; +namespace Snap.Hutao.Model.InterChange.GachaLog; internal sealed class UIGFEntry { @@ -16,4 +16,7 @@ internal sealed class UIGFEntry [JsonPropertyName("list")] public required List List { get; set; } + + [JsonIgnore] + public bool IsSelected { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs similarity index 91% rename from src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFInfo.cs rename to src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs index fabdb0cd..0cd35890 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/UIGFInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Model.InterChange; +namespace Snap.Hutao.Model.InterChange.GachaLog; internal sealed class UIGFInfo { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReserved.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReserved.cs deleted file mode 100644 index e6b7d086..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReserved.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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; } - - public List>? Achievement { get; set; } - - public List>? AvatarInfo { get; set; } - - public List>? Cultivation { get; set; } - - public List>? SpiralAbyss { get; set; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedAchievement.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedAchievement.cs deleted file mode 100644 index 65a9b953..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedAchievement.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core.Abstraction; -using Snap.Hutao.Model.Intrinsic; - -namespace Snap.Hutao.Model.InterChange; - -internal sealed class HutaoReservedAchievement : IMappingFrom -{ - public required uint Id { get; set; } - - public required uint Current { get; set; } - - public required DateTimeOffset Time { get; set; } - - public required AchievementStatus Status { get; set; } - - public static HutaoReservedAchievement From(Entity.Achievement source) - { - return new() - { - Id = source.Id, - Current = source.Current, - Time = source.Time, - Status = source.Status, - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationEntry.cs deleted file mode 100644 index 54c49085..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationEntry.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Model.Entity.Primitive; - -namespace Snap.Hutao.Model.InterChange; - -internal sealed class HutaoReservedCultivationEntry -{ - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint AvatarLevelFrom { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint AvatarLevelTo { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillALevelFrom { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillALevelTo { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillELevelFrom { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillELevelTo { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillQLevelFrom { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint SkillQLevelTo { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint WeaponLevelFrom { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public uint WeaponLevelTo { get; set; } - - public required CultivateType Type { get; set; } - - public required uint Id { get; set; } - - public required List Items { get; set; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationItem.cs deleted file mode 100644 index 0b6a992b..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedCultivationItem.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core.Abstraction; -using Snap.Hutao.Model.Entity; - -namespace Snap.Hutao.Model.InterChange; - -internal sealed class HutaoReservedCultivationItem : IMappingFrom -{ - public required uint ItemId { get; set; } - - public required uint Count { get; set; } - - public required bool IsFinished { get; set; } - - public static HutaoReservedCultivationItem From(CultivateItem item) - { - return new() - { - ItemId = item.ItemId, - Count = item.Count, - IsFinished = item.IsFinished, - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedEntry.cs deleted file mode 100644 index e7746593..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Model.InterChange; - -internal sealed class HutaoReservedEntry -{ - public required string Identity { get; set; } - - public required List List { get; set; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedSpiralAbyssEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedSpiralAbyssEntry.cs deleted file mode 100644 index 3ffa9446..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/HutaoReservedSpiralAbyssEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Model.InterChange; - -internal sealed class HutaoReservedSpiralAbyssEntry -{ - public required uint ScheduleId { get; set; } - - public required Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss SpiralAbyss { get; set; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 50c8f363..682a9c87 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1802,6 +1802,18 @@ 保存游戏路径失败 + + 导入的 UIGF 文件中包含 UID 重复的祈愿记录项 + + + 导入的 UIGF 文件中不包含祈愿数据 + + + 请选择至少一个 UID 以导入数据 + + + 导入成功 + 用户 [{0}] 添加成功 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs index a5061dcf..4ade25d6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs @@ -31,6 +31,28 @@ internal sealed partial class AvatarInfoDbBulkOperation private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; + public void UnsafeUpdateDbAvatarInfos(string uid, IEnumerable webInfos) + { + List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); + EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); + + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + foreach (EnkaAvatarInfo webInfo in webInfos) + { + if (AvatarIds.IsPlayer(webInfo.AvatarId)) + { + continue; + } + + EntityAvatarInfo? entity = dbInfoMap.GetValueOrDefault(webInfo.AvatarId); + AddOrUpdateAvatarInfo(entity, uid, appDbContext, webInfo); + } + } + } + public async ValueTask> UpdateDbAvatarInfosByShowcaseAsync(string uid, IEnumerable webInfos, CancellationToken token) { await taskContext.SwitchToBackgroundAsync(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs index bdd018f8..4b8c0836 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs @@ -110,4 +110,9 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService { this.Delete(i => i.ArchiveId == archiveId && i.QueryType == queryType && i.Id >= endId); } + + public List GetGachaArchiveList() + { + return this.List(); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index 4cb8b280..2e9f695a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -5,7 +5,6 @@ using Snap.Hutao.Core.Database; using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.InterChange.GachaLog; using Snap.Hutao.Service.GachaLog.Factory; using Snap.Hutao.Service.GachaLog.QueryProvider; using Snap.Hutao.Service.Metadata; @@ -22,8 +21,6 @@ internal sealed partial class GachaLogService : IGachaLogService { private readonly IGachaStatisticsSlimFactory gachaStatisticsSlimFactory; private readonly IGachaStatisticsFactory gachaStatisticsFactory; - private readonly IUIGFExportService gachaLogExportService; - private readonly IUIGFImportService gachaLogImportService; private readonly IGachaLogDbService gachaLogDbService; private readonly IServiceProvider serviceProvider; private readonly IMetadataService metadataService; @@ -85,17 +82,6 @@ internal sealed partial class GachaLogService : IGachaLogService return statistics; } - public ValueTask ExportToUIGFAsync(GachaArchive archive) - { - return gachaLogExportService.ExportAsync(context, archive); - } - - public async ValueTask ImportFromUIGFAsync(LegacyUIGF uigf) - { - ArgumentNullException.ThrowIfNull(Archives); - await gachaLogImportService.ImportAsync(context, uigf, Archives).ConfigureAwait(false); - } - public async ValueTask RefreshGachaLogAsync(GachaLogQuery query, RefreshStrategyKind kind, IProgress progress, CancellationToken token) { bool isLazy = kind switch diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs index 70fe771c..68e4be57 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs @@ -22,6 +22,8 @@ internal interface IGachaLogDbService : IAppDbService, IAppDbServi GachaArchive? GetGachaArchiveByUid(string uid); + List GetGachaArchiveList(); + ObservableCollection GetGachaArchiveCollection(); List GetGachaItemListByArchiveId(Guid archiveId); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogService.cs index 478701df..b01e7d27 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogService.cs @@ -19,56 +19,13 @@ internal interface IGachaLogService ValueTask EnsureArchiveInCollectionAsync(Guid archiveId, CancellationToken token = default(CancellationToken)); - /// - /// 导出为一个新的UIGF对象 - /// - /// 存档 - /// UIGF对象 - ValueTask ExportToUIGFAsync(GachaArchive archive); - - /// - /// 获得对应的祈愿统计 - /// - /// 存档 - /// 祈愿统计 ValueTask GetStatisticsAsync(GachaArchive archive); - /// - /// 异步获取简化的祈愿统计列表 - /// - /// 取消令牌 - /// 简化的祈愿统计列表 ValueTask> GetStatisticsSlimListAsync(CancellationToken token = default); - /// - /// 异步从UIGF导入数据 - /// - /// 信息 - /// 任务 - ValueTask ImportFromUIGFAsync(LegacyUIGF uigf); - - /// - /// 异步初始化 - /// - /// 取消令牌 - /// 是否初始化成功 ValueTask InitializeAsync(CancellationToken token = default); - /// - /// 刷新祈愿记录 - /// 切换选中的存档 - /// - /// 查询语句 - /// 刷新策略 - /// 进度 - /// 取消令牌 - /// 验证密钥是否有效 ValueTask RefreshGachaLogAsync(GachaLogQuery query, RefreshStrategyKind strategy, IProgress progress, CancellationToken token); - /// - /// 删除存档 - /// - /// 存档 - /// 任务 ValueTask RemoveArchiveAsync(GachaArchive archive); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFExportService.cs deleted file mode 100644 index 85c7585d..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFExportService.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.InterChange.GachaLog; - -namespace Snap.Hutao.Service.GachaLog; - -/// -/// 祈愿记录导出服务 -/// -internal interface IUIGFExportService -{ - /// - /// 异步导出存档到 UIGF - /// - /// 元数据上下文 - /// 存档 - /// UIGF - ValueTask ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive); -} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFImportService.cs deleted file mode 100644 index 88300475..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IUIGFImportService.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core.Database; -using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.InterChange.GachaLog; - -namespace Snap.Hutao.Service.GachaLog; - -/// -/// 祈愿记录导入服务 -/// -internal interface IUIGFImportService -{ - ValueTask ImportAsync(GachaLogServiceMetadataContext context, LegacyUIGF uigf, AdvancedDbCollectionView archives); -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryProviderFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryProviderFactory.cs index 2494cc5c..d24363c6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryProviderFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryProviderFactory.cs @@ -13,6 +13,7 @@ internal sealed partial class GachaLogQueryProviderFactory : IGachaLogQueryProvi public IGachaLogQueryProvider Create(RefreshOption option) { + // TODO: replace with keyed services return option switch { RefreshOption.SToken => serviceProvider.GetRequiredService(), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs deleted file mode 100644 index d70d3182..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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.GachaLog; - -namespace Snap.Hutao.Service.GachaLog; - -/// -/// 祈愿记录导出服务 -/// -[ConstructorGenerated] -[Injection(InjectAs.Scoped, typeof(IUIGFExportService))] -internal sealed partial class UIGFExportService : IUIGFExportService -{ - private readonly IGachaLogDbService gachaLogDbService; - private readonly RuntimeOptions runtimeOptions; - private readonly CultureOptions cultureOptions; - private readonly ITaskContext taskContext; - - /// - public async ValueTask ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive) - { - await taskContext.SwitchToBackgroundAsync(); - List entities = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); - List list = entities.SelectList(i => LegacyUIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId))); - - LegacyUIGF uigf = new() - { - Info = LegacyUIGFInfo.From(runtimeOptions, cultureOptions, archive.Uid), - List = list, - }; - - return uigf; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs deleted file mode 100644 index 13bec82d..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core.Database; -using Snap.Hutao.Core.ExceptionService; -using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.InterChange.GachaLog; -using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; - -namespace Snap.Hutao.Service.GachaLog; - -[ConstructorGenerated] -[Injection(InjectAs.Scoped, typeof(IUIGFImportService))] -internal sealed partial class UIGFImportService : IUIGFImportService -{ - private readonly IGachaLogDbService gachaLogDbService; - private readonly ILogger logger; - private readonly CultureOptions cultureOptions; - private readonly ITaskContext taskContext; - - public async ValueTask ImportAsync(GachaLogServiceMetadataContext context, LegacyUIGF uigf, AdvancedDbCollectionView archives) - { - await taskContext.SwitchToBackgroundAsync(); - - if (!uigf.IsCurrentVersionSupported(out LegacyUIGFVersion version)) - { - HutaoException.InvalidOperation(SH.ServiceUIGFImportUnsupportedVersion); - } - - // v2.3+ supports any locale - // v2.2 only supports matched locale - // v2.1 only supports CHS - if (version is LegacyUIGFVersion.Major2Minor2OrLower) - { - if (!cultureOptions.LanguageCodeFitsCurrentLocale(uigf.Info.Language)) - { - string message = SH.FormatServiceGachaUIGFImportLanguageNotMatch(uigf.Info.Language, cultureOptions.LanguageCode); - HutaoException.InvalidOperation(message); - } - - if (!uigf.IsMajor2Minor2OrLowerListValid(out long id)) - { - string message = SH.FormatServiceGachaLogUIGFImportItemInvalidFormat(id); - HutaoException.InvalidOperation(message); - } - } - - if (version is LegacyUIGFVersion.Major2Minor3OrHigher) - { - if (!uigf.IsMajor2Minor3OrHigherListValid(out long id)) - { - string message = SH.FormatServiceGachaLogUIGFImportItemInvalidFormat(id); - HutaoException.InvalidOperation(message); - } - } - - GachaArchiveOperation.GetOrAdd(gachaLogDbService, taskContext, uigf.Info.Uid, archives, out GachaArchive? archive); - Guid archiveId = archive.InnerId; - - List fullItems = []; - foreach (GachaType queryType in GachaLog.QueryTypes) - { - long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType); - logger.LogInformation("Last Id to trim with: [{Id}]", trimId); - - List currentTypedList = version switch - { - LegacyUIGFVersion.Major2Minor3OrHigher => uigf.List - .Where(item => item.UIGFGachaType == queryType && item.Id < trimId) - .OrderByDescending(item => item.Id) - .Select(item => GachaItem.From(archiveId, item)) - .ToList(), - 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))) - .ToList(), - _ => throw HutaoException.NotSupported(), - }; - - ThrowIfContainsInvalidItem(currentTypedList); - fullItems.AddRange(currentTypedList); - } - - gachaLogDbService.AddGachaItemRange(fullItems); - - await taskContext.SwitchToMainThreadAsync(); - archives.MoveCurrentTo(archive); - } - - private static void ThrowIfContainsInvalidItem(List list) - { - // 越早的记录手工导入的可能性越高 - // 错误率相对来说会更高 - // 因此从尾部开始查找 - if (list.LastOrDefault(item => item.ItemId is 0U) is { } item) - { - HutaoException.InvalidOperation(SH.FormatServiceGachaLogUIGFImportItemInvalidFormat(item.Id)); - } - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameServiceFacade.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameServiceFacade.cs index c7331ad2..fcff98b9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameServiceFacade.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameServiceFacade.cs @@ -8,50 +8,22 @@ using Snap.Hutao.Service.Game.Configuration; namespace Snap.Hutao.Service.Game; -/// -/// 游戏服务 -/// -[HighQuality] internal interface IGameServiceFacade { - /// - /// 游戏内账号集合 - /// ObservableReorderableDbCollection GameAccountCollection { get; } + ValueTask AttachGameAccountToUidAsync(GameAccount gameAccount, string uid); ValueTask DetectGameAccountAsync(SchemeType scheme); - /// - /// 异步获取游戏路径 - /// - /// 结果 ValueTask> GetGamePathAsync(); - /// - /// 获取多通道值 - /// - /// 多通道值 ChannelOptions GetChannelOptions(); - /// - /// 游戏是否正在运行 - /// - /// 是否正在运行 bool IsGameRunning(); - /// - /// 异步修改游戏账号名称 - /// - /// 游戏账号 - /// 任务 ValueTask ModifyGameAccountAsync(GameAccount gameAccount); - /// - /// 异步尝试移除账号 - /// - /// 账号 - /// 任务 ValueTask RemoveGameAccountAsync(GameAccount gameAccount); GameAccount? DetectCurrentGameAccount(SchemeType scheme); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFExportService.cs index 6250164d..3c86466a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFExportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFExportService.cs @@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.UIGF; internal interface IUIGFExportService { - ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token); + ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFImportService.cs index 8cf66656..c481485b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFImportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFImportService.cs @@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.UIGF; internal interface IUIGFImportService { - ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token); + ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs index 8c053dff..afef414a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/IUIGFService.cs @@ -5,5 +5,7 @@ namespace Snap.Hutao.Service.UIGF; internal interface IUIGFService { - ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token); + ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token = default); + + ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token = default); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ExportService.cs index fbc31f23..2bd3c870 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ExportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ExportService.cs @@ -3,14 +3,9 @@ using Snap.Hutao.Core; using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.InterChange; -using Snap.Hutao.Service.Achievement; -using Snap.Hutao.Service.AvatarInfo; -using Snap.Hutao.Service.Cultivation; +using Snap.Hutao.Model.InterChange.GachaLog; using Snap.Hutao.Service.GachaLog; -using Snap.Hutao.Service.SpiralAbyss; using System.IO; -using System.Runtime.InteropServices; namespace Snap.Hutao.Service.UIGF; @@ -23,11 +18,11 @@ internal sealed partial class UIGF40ExportService : IUIGFExportService private readonly RuntimeOptions runtimeOptions; private readonly ITaskContext taskContext; - public async ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token) + public async ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token = default) { await taskContext.SwitchToBackgroundAsync(); - Model.InterChange.UIGF uigf = new() + Model.InterChange.GachaLog.UIGF uigf = new() { Info = new() { @@ -36,27 +31,17 @@ internal sealed partial class UIGF40ExportService : IUIGFExportService ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(), Version = "v4.0", }, - HutaoReserved = new() - { - Version = 1, - }, }; ExportGachaArchives(uigf, exportOptions.GachaArchiveIds); - ExportAchievementArchives(uigf.HutaoReserved, exportOptions.ReservedAchievementArchiveIds); - ExportAvatarInfoUids(uigf.HutaoReserved, exportOptions.ReservedAvatarInfoUids); - ExportCultivationProjects(uigf.HutaoReserved, exportOptions.ReservedCultivationProjectIds); - ExportSpialAbysses(uigf.HutaoReserved, exportOptions.ReservedSpiralAbyssUids); 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 archiveIds) + private void ExportGachaArchives(Model.InterChange.GachaLog.UIGF uigf, List archiveIds) { if (archiveIds.Count <= 0) { @@ -83,138 +68,4 @@ internal sealed partial class UIGF40ExportService : IUIGFExportService uigf.Hk4e = results; } - - private void ExportAchievementArchives(HutaoReserved hutaoReserved, List archiveIds) - { - if (archiveIds.Count <= 0) - { - return; - } - - IAchievementDbService achievementDbService = serviceProvider.GetRequiredService(); - - List> results = []; - foreach (Guid archiveId in archiveIds) - { - AchievementArchive? archive = achievementDbService.GetAchievementArchiveById(archiveId); - ArgumentNullException.ThrowIfNull(archive); - List dbItems = achievementDbService.GetAchievementListByArchiveId(archiveId); - HutaoReservedEntry entry = new() - { - Identity = archive.Name, - List = dbItems.SelectList(HutaoReservedAchievement.From), - }; - - results.Add(entry); - } - - hutaoReserved.Achievement = results; - } - - private void ExportAvatarInfoUids(HutaoReserved hutaoReserved, List uids) - { - if (uids.Count <= 0) - { - return; - } - - IAvatarInfoDbService avatarInfoDbService = serviceProvider.GetRequiredService(); - - List> results = []; - foreach (string uid in uids) - { - List? dbItems = avatarInfoDbService.GetAvatarInfoListByUid(uid); - HutaoReservedEntry entry = new() - { - Identity = uid, - List = dbItems.SelectList(item => item.Info), - }; - - results.Add(entry); - } - - hutaoReserved.AvatarInfo = results; - } - - private void ExportCultivationProjects(HutaoReserved hutaoReserved, List projectIds) - { - if (projectIds.Count <= 0) - { - return; - } - - ICultivationDbService cultivationDbService = serviceProvider.GetRequiredService(); - - List> results = []; - foreach (Guid projectId in projectIds) - { - CultivateProject? project = cultivationDbService.GetCultivateProjectById(projectId); - ArgumentNullException.ThrowIfNull(project); - List entries = cultivationDbService.GetCultivateEntryListIncludingLevelInformationByProjectId(projectId); - - List innerResults = []; - foreach (ref readonly CultivateEntry innerEntry in CollectionsMarshal.AsSpan(entries)) - { - List items = cultivationDbService.GetCultivateItemListByEntryId(innerEntry.InnerId); - - HutaoReservedCultivationEntry innerResultEntry = new() - { - AvatarLevelFrom = innerEntry.LevelInformation?.AvatarLevelFrom ?? 0, - AvatarLevelTo = innerEntry.LevelInformation?.AvatarLevelTo ?? 0, - SkillALevelFrom = innerEntry.LevelInformation?.SkillALevelFrom ?? 0, - SkillALevelTo = innerEntry.LevelInformation?.SkillALevelTo ?? 0, - SkillELevelFrom = innerEntry.LevelInformation?.SkillELevelFrom ?? 0, - SkillELevelTo = innerEntry.LevelInformation?.SkillELevelTo ?? 0, - SkillQLevelFrom = innerEntry.LevelInformation?.SkillQLevelFrom ?? 0, - SkillQLevelTo = innerEntry.LevelInformation?.SkillQLevelTo ?? 0, - WeaponLevelFrom = innerEntry.LevelInformation?.WeaponLevelFrom ?? 0, - WeaponLevelTo = innerEntry.LevelInformation?.WeaponLevelTo ?? 0, - Type = innerEntry.Type, - Id = innerEntry.Id, - Items = items.SelectList(HutaoReservedCultivationItem.From), - }; - - innerResults.Add(innerResultEntry); - } - - HutaoReservedEntry outerEntry = new() - { - Identity = project.Name, - List = innerResults, - }; - - results.Add(outerEntry); - } - - hutaoReserved.Cultivation = results; - } - - private void ExportSpialAbysses(HutaoReserved hutaoReserved, List uids) - { - if (uids.Count <= 0) - { - return; - } - - ISpiralAbyssRecordDbService spiralAbyssRecordDbService = serviceProvider.GetRequiredService(); - - List> results = []; - foreach (string uid in uids) - { - Dictionary dbMap = spiralAbyssRecordDbService.GetSpiralAbyssEntryMapByUid(uid); - HutaoReservedEntry entry = new() - { - Identity = uid, - List = dbMap.Select(item => new HutaoReservedSpiralAbyssEntry - { - ScheduleId = item.Key, - SpiralAbyss = item.Value.SpiralAbyss, - }).ToList(), - }; - - results.Add(entry); - } - - hutaoReserved.SpiralAbyss = results; - } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ImportService.cs index 0e182d15..91a1ab6a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ImportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGF40ImportService.cs @@ -1,10 +1,8 @@ // 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.Achievement; +using Snap.Hutao.Model.InterChange.GachaLog; using Snap.Hutao.Service.GachaLog; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; @@ -14,18 +12,13 @@ namespace Snap.Hutao.Service.UIGF; [Injection(InjectAs.Transient, typeof(IUIGFImportService), Key = UIGFVersion.UIGF40)] internal sealed partial class UIGF40ImportService : IUIGFImportService { - private readonly JsonSerializerOptions jsonOptions; private readonly IServiceProvider serviceProvider; - private readonly RuntimeOptions runtimeOptions; private readonly ITaskContext taskContext; - public async ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token) + public async ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token = default) { await taskContext.SwitchToBackgroundAsync(); ImportGachaArchives(importOptions.UIGF.Hk4e, importOptions.GachaArchiveUids); - ImportAchievementArchives(importOptions.UIGF.HutaoReserved?.Achievement, importOptions.ReservedAchievementArchiveIdentities); - - return true; } private void ImportGachaArchives(List>? entries, HashSet uids) @@ -70,36 +63,4 @@ internal sealed partial class UIGF40ImportService : IUIGFImportService gachaLogDbService.AddGachaItemRange(fullItems); } } - - private void ImportAchievementArchives(List>? entries, HashSet identities) - { - if (entries.IsNullOrEmpty() || identities.IsNullOrEmpty()) - { - return; - } - - IAchievementDbService achievementDbService = serviceProvider.GetRequiredService(); - AchievementDbBulkOperation achievementDbBulkOperation = serviceProvider.GetRequiredService(); - - foreach (HutaoReservedEntry entry in entries) - { - if (!identities.Contains(entry.Identity)) - { - continue; - } - - AchievementArchive? archive = achievementDbService.GetAchievementArchiveByName(entry.Identity); - - if (archive is null) - { - archive = AchievementArchive.From(entry.Identity); - achievementDbService.AddAchievementArchive(archive); - } - - Guid archiveId = archive.InnerId; - - List achievements = entry.List.SelectList(item => Model.Entity.Achievement.From(archiveId, item)); - achievementDbBulkOperation.Overwrite(archiveId, achievements); - } - } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs index 352b5880..62c8ab58 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFExportOptions.cs @@ -8,12 +8,4 @@ internal sealed class UIGFExportOptions public required string FilePath { get; set; } public required List GachaArchiveIds { get; set; } - - public required List ReservedAchievementArchiveIds { get; set; } - - public required List ReservedAvatarInfoUids { get; set; } - - public required List ReservedCultivationProjectIds { get; set; } - - public required List ReservedSpiralAbyssUids { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFImportOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFImportOptions.cs index c5fc6677..9ebfb237 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFImportOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFImportOptions.cs @@ -5,15 +5,7 @@ namespace Snap.Hutao.Service.UIGF; internal sealed class UIGFImportOptions { - public required Model.InterChange.UIGF UIGF { get; set; } + public required Model.InterChange.GachaLog.UIGF UIGF { get; set; } public required HashSet GachaArchiveUids { get; set; } - - public required HashSet ReservedAchievementArchiveIdentities { get; set; } - - public required HashSet ReservedAvatarInfoIdentities { get; set; } - - public required HashSet ReservedCultivationProjectIdentities { get; set; } - - public required HashSet ReservedSpiralAbyssIdentities { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs index a5d5ee9d..a5575695 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/UIGF/UIGFService.cs @@ -4,14 +4,20 @@ namespace Snap.Hutao.Service.UIGF; [ConstructorGenerated] -[Injection(InjectAs.Transient, typeof(IUIGFService))] +[Injection(InjectAs.Singleton, typeof(IUIGFService))] internal sealed partial class UIGFService : IUIGFService { private readonly IServiceProvider serviceProvider; - public ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token) + public ValueTask ExportAsync(UIGFExportOptions exportOptions, CancellationToken token = default) { IUIGFExportService exportService = serviceProvider.GetRequiredKeyedService(UIGFVersion.UIGF40); return exportService.ExportAsync(exportOptions, token); } + + public ValueTask ImportAsync(UIGFImportOptions importOptions, CancellationToken token = default) + { + IUIGFImportService importService = serviceProvider.GetRequiredKeyedService(UIGFVersion.UIGF40); + return importService.ImportAsync(importOptions, token); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index fea0b97e..98b85142 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -150,6 +150,7 @@ + @@ -339,6 +340,11 @@ + + + MSBuild:Compile + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Data/Converter/Specialized/UInt32ToGradientColorConverter.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Data/Converter/Specialized/UInt32ToGradientColorConverter.cs index c75cbf12..ba5b18d4 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Data/Converter/Specialized/UInt32ToGradientColorConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Data/Converter/Specialized/UInt32ToGradientColorConverter.cs @@ -38,4 +38,13 @@ internal sealed partial class UInt32ToGradientColorConverter : DependencyValueCo color.B = (byte)b; return color; } +} + +internal sealed class TimestampToLocalTimeStringConverter : ValueConverter +{ + public override string Convert(long from) + { + DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(from).ToLocalTime(); + return $"{dto:yyyy-MM-dd HH:mm:ss}"; + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml new file mode 100644 index 00000000..2d54ebe2 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml.cs new file mode 100644 index 00000000..778ea833 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFImportDialog.xaml.cs @@ -0,0 +1,35 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Model.InterChange.GachaLog; + +namespace Snap.Hutao.UI.Xaml.View.Dialog; + +[DependencyProperty("UIGF", typeof(UIGF))] +[DependencyProperty("Selections", typeof(List))] +internal sealed partial class UIGFImportDialog : ContentDialog +{ + private readonly ITaskContext taskContext; + + public UIGFImportDialog(IServiceProvider serviceProvider, UIGF uigf) + { + InitializeComponent(); + taskContext = serviceProvider.GetRequiredService(); + + UIGF = uigf; + Selections = uigf.Hk4e?.SelectList(item => new UIGFUidSelection(item.Uid)); + } + + public async ValueTask>> GetSelectedUidsAsync() + { + await taskContext.SwitchToMainThreadAsync(); + if (await ShowAsync() is ContentDialogResult.Primary) + { + HashSet uids = Selections.Where(item => item.IsSelected).Select(item => item.Uid).ToHashSet(); + return new(true, uids); + } + + return new(false, default!); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFUidSelection.xaml.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFUidSelection.xaml.cs new file mode 100644 index 00000000..430713a0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/UIGFUidSelection.xaml.cs @@ -0,0 +1,22 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Model.InterChange.GachaLog; + +namespace Snap.Hutao.UI.Xaml.View.Dialog; + +internal sealed class UIGFUidSelection : ObservableObject +{ + private bool isSelected = true; + + public UIGFUidSelection(string uid) + { + Uid = uid; + } + + public bool IsSelected { get => isSelected; set => SetProperty(ref isSelected, value); } + + public string Uid { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/SettingPage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/SettingPage.xaml index 6ada0c23..eae3bd52 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/SettingPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/SettingPage.xaml @@ -114,6 +114,7 @@ Padding="16" Spacing="16"> + @@ -193,43 +194,40 @@ - + + -