diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs deleted file mode 100644 index 2f940eb7..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using CommunityToolkit.Mvvm.Messaging; -using CommunityToolkit.WinUI.Behaviors; -using Microsoft.UI.Xaml.Controls; - -namespace Snap.Hutao.Control.Behavior; - -/// -/// AppTitleBar Workaround -/// https://github.com/microsoft/microsoft-ui-xaml/issues/7756 -/// -internal sealed class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase -{ - private readonly IMessenger messenger; - private readonly EventHandler dropDownOpenedHandler; - private readonly EventHandler dropDownClosedHandler; - - /// - /// AppTitleBar Workaround - /// - public ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior() - { - messenger = Ioc.Default.GetRequiredService(); - dropDownOpenedHandler = OnDropDownOpened; - dropDownClosedHandler = OnDropDownClosed; - } - - /// - protected override bool Initialize() - { - AssociatedObject.DropDownOpened += dropDownOpenedHandler; - AssociatedObject.DropDownClosed += dropDownClosedHandler; - return true; - } - - /// - protected override bool Uninitialize() - { - AssociatedObject.DropDownOpened -= dropDownOpenedHandler; - AssociatedObject.DropDownClosed -= dropDownClosedHandler; - return true; - } - - private void OnDropDownOpened(object? sender, object e) - { - messenger.Send(Message.FlyoutStateChangedMessage.Open); - } - - private void OnDropDownClosed(object? sender, object e) - { - messenger.Send(Message.FlyoutStateChangedMessage.Close); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/CurrentWindowReference.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/CurrentWindowReference.cs index ce9cbdda..6c880a8b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/CurrentWindowReference.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/CurrentWindowReference.cs @@ -1,22 +1,23 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using CommunityToolkit.WinUI.Notifications; -using Microsoft.Extensions.Caching.Memory; using Microsoft.UI.Xaml; -using Microsoft.Windows.AppLifecycle; -using Snap.Hutao.Core.Setting; -using Snap.Hutao.Service.DailyNote; -using Snap.Hutao.Service.Hutao; -using Snap.Hutao.Service.Metadata; -using Snap.Hutao.Service.Navigation; -using Snap.Hutao.ViewModel.Guide; -using System.Diagnostics; namespace Snap.Hutao.Core.LifeCycle; [Injection(InjectAs.Singleton, typeof(ICurrentWindowReference))] internal sealed class CurrentWindowReference : ICurrentWindowReference { - public Window Window { get; set; } = default!; + private readonly WeakReference reference = new(default!); + + [SuppressMessage("", "SH007")] + public Window Window + { + get + { + reference.TryGetTarget(out Window? window); + return window!; + } + set => reference.SetTarget(value); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/Feature.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/Feature.cs deleted file mode 100644 index 1731886c..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/Feature.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using CommunityToolkit.Mvvm.ComponentModel; - -namespace Snap.Hutao.Core.Setting; - -/// -/// 功能 -/// -internal sealed class Feature : ObservableObject -{ - private readonly string displayName; - private readonly string description; - private readonly string settingKey; - private readonly bool defaultValue; - - /// - /// 构造一个新的功能 - /// - /// 显示名称 - /// 描述 - /// 键 - /// 默认值 - public Feature(string displayName, string description, string settingKey, bool defaultValue) - { - this.displayName = displayName; - this.description = description; - this.settingKey = settingKey; - this.defaultValue = defaultValue; - } - - /// - /// 显示名称 - /// - public string DisplayName { get => displayName; } - - /// - /// 描述 - /// - public string Description { get => description; } - - /// - /// 值 - /// - public bool Value - { - get => LocalSetting.Get(settingKey, defaultValue); - set - { - LocalSetting.Set(settingKey, value); - OnPropertyChanged(); - } - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/FeatureOptions.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/FeatureOptions.cs deleted file mode 100644 index 7039ecb2..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/FeatureOptions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using System.Collections; - -namespace Snap.Hutao.Core.Setting; - -/// -/// 功能选项 -/// -internal sealed class FeatureOptions : IReadOnlyCollection -{ - /// - /// 启用实时便笺无感验证 - /// - public Feature IsDailyNoteSilentVerificationEnabled { get; } = new( - "IsDailyNoteSilentVerificationEnabled", "启用实时便笺无感验证", "IsDailyNoteSilentVerificationEnabled", true); - - /// - /// 元数据检查是否忽略 - /// - public Feature IsMetadataUpdateCheckSuppressed { get; } = new( - "IsMetadataUpdateCheckSuppressed", "禁用元数据更新检查", "IsMetadataUpdateCheckSuppressed", false); - - /// - public int Count { get => 2; } - - /// - public IEnumerator GetEnumerator() - { - // TODO: Use source generator - yield return IsDailyNoteSilentVerificationEnabled; - yield return IsMetadataUpdateCheckSuppressed; - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs index 858545b0..6873e1fc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs @@ -76,4 +76,9 @@ internal static class SettingKeys public const string CultivationWeapon90LevelTarget = "CultivationWeapon90LevelTarget"; public const string CultivationWeapon70LevelCurrent = "CultivationWeapon70LevelCurrent"; public const string CultivationWeapon70LevelTarget = "CultivationWeapon70LevelTarget"; + + public const string IsHomeCardLaunchGamePresented = "IsHomeCardLaunchGamePresented"; + public const string IsHomeCardGachaStatisticsPresented = "IsHomeCardGachaStatisticsPresented"; + public const string IsHomeCardAchievementPresented = "IsHomeCardAchievementPresented"; + public const string IsHomeCardDailyNotePresented = "IsHomeCardDailyNotePresented"; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Shell/ShellLinkInterop.cs b/src/Snap.Hutao/Snap.Hutao/Core/Shell/ShellLinkInterop.cs index f5e6d5e1..59d49527 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Shell/ShellLinkInterop.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Shell/ShellLinkInterop.cs @@ -17,6 +17,10 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop public void CreateDesktopShoutcutForElevatedLaunch() { + string sourceLogoPath = Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"); + string targetLogoPath = Path.Combine(runtimeOptions.DataFolder, "ShellLinkLogo.ico"); + File.Copy(sourceLogoPath, targetLogoPath); + IShellLinkW shellLink = (IShellLinkW)new ShellLink(); shellLink.SetPath("powershell"); shellLink.SetArguments($""" @@ -24,8 +28,7 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop """); shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_SHOWMINNOACTIVE); - string iconPath = Path.Combine(runtimeOptions.InstalledLocation, "Snap.Hutao.exe"); - shellLink.SetIconLocation(iconPath, 0); + shellLink.SetIconLocation(targetLogoPath, 0); string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); string target = Path.Combine(desktop, $"{SH.AppNameAndVersion.Format(runtimeOptions.Version)}.lnk"); diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs index 4d6334ff..e6b06c89 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs @@ -22,9 +22,6 @@ internal sealed class CalculableWeapon IMappingFrom, IMappingFrom { - private uint levelCurrent; - private uint levelTarget; - /// /// 构造一个新的可计算武器 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs index 61b785ed..99ceee44 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs @@ -13,32 +13,8 @@ internal sealed class UIIFItem /// 物品Id /// [JsonPropertyName("itemId")] - public int ItemId { get; set; } + public uint ItemId { get; set; } - /// - /// 物品Id - /// - [JsonPropertyName("count")] - public int Count { get; set; } - - /// - /// 等级 - /// Reliquary/Weapon - /// - [JsonPropertyName("level")] - public int? Level { get; set; } - - /// - /// 副属性列表 - /// Reliquary - /// - [JsonPropertyName("appendPropIdList")] - public List? AppendPropIdList { get; set; } = default!; - - /// - /// 精炼等级 0-4 - /// Weapon - /// - [JsonPropertyName("promoteLevel")] - public int? PromoteLevel { get; set; } + [JsonPropertyName("material")] + public UIIFMaterial Material { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFMaterial.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFMaterial.cs new file mode 100644 index 00000000..e4754492 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFMaterial.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.InterChange.Inventory; + +internal sealed class UIIFMaterial +{ + public uint Count { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/BlurBackground.png b/src/Snap.Hutao/Snap.Hutao/Resource/BlurBackground.png new file mode 100644 index 00000000..40fcf94e Binary files /dev/null and b/src/Snap.Hutao/Snap.Hutao/Resource/BlurBackground.png differ diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index 6ba9a2fe..f5fe92d6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -5245,7 +5245,7 @@ namespace Snap.Hutao.Resource.Localization { } /// - /// 查找类似 在桌面上创建默认以管理员方式启动的快捷方式,更新后需要重新创建 的本地化字符串。 + /// 查找类似 在桌面上创建默认以管理员方式启动的快捷方式 的本地化字符串。 /// internal static string ViewPageSettingCreateDesktopShortcutDescription { get { @@ -5469,6 +5469,87 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 管理主页仪表板中的卡片 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardDescription { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardDescription", resourceCulture); + } + } + + /// + /// 查找类似 主页卡片 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardHeader", resourceCulture); + } + } + + /// + /// 查找类似 成就管理 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardItemAchievementHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardItemAchievementHeader", resourceCulture); + } + } + + /// + /// 查找类似 实时便笺 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardItemDailyNoteHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardItemDailyNoteHeader", resourceCulture); + } + } + + /// + /// 查找类似 祈愿记录 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardItemgachaStatisticsHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardItemgachaStatisticsHeader", resourceCulture); + } + } + + /// + /// 查找类似 启动游戏 的本地化字符串。 + /// + internal static string ViewpageSettingHomeCardItemLaunchGameHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeCardItemLaunchGameHeader", resourceCulture); + } + } + + /// + /// 查找类似 隐藏 的本地化字符串。 + /// + internal static string ViewPageSettingHomeCardOff { + get { + return ResourceManager.GetString("ViewPageSettingHomeCardOff", resourceCulture); + } + } + + /// + /// 查找类似 显示 的本地化字符串。 + /// + internal static string ViewPageSettingHomeCardOn { + get { + return ResourceManager.GetString("ViewPageSettingHomeCardOn", resourceCulture); + } + } + + /// + /// 查找类似 主页 的本地化字符串。 + /// + internal static string ViewpageSettingHomeHeader { + get { + return ResourceManager.GetString("ViewpageSettingHomeHeader", resourceCulture); + } + } + /// /// 查找类似 胡桃账号 的本地化字符串。 /// @@ -5577,6 +5658,15 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号 的本地化字符串。 + /// + internal static string ViewPageSettingSetPowerShellDescription { + get { + return ResourceManager.GetString("ViewPageSettingSetPowerShellDescription", resourceCulture); + } + } + /// /// 查找类似 PowerShell 路径 的本地化字符串。 /// @@ -5586,6 +5676,15 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 Shell 体验 的本地化字符串。 + /// + internal static string ViewPageSettingShellExperienceHeader { + get { + return ResourceManager.GetString("ViewPageSettingShellExperienceHeader", resourceCulture); + } + } + /// /// 查找类似 赞助我们 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 64cd1173..b2a94458 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1902,7 +1902,7 @@ 创建 - 在桌面上创建默认以管理员方式启动的快捷方式,更新后需要重新创建 + 在桌面上创建默认以管理员方式启动的快捷方式 创建快捷方式 @@ -1976,6 +1976,33 @@ 无感验证 + + 管理主页仪表板中的卡片 + + + 主页卡片 + + + 成就管理 + + + 实时便笺 + + + 祈愿记录 + + + 启动游戏 + + + 隐藏 + + + 显示 + + + 主页 + 胡桃账号 @@ -2012,9 +2039,15 @@ 设置游戏路径时,请选择游戏本体(YuanShen.exe 或 GenshinImpact.exe)而不是启动器(launcher.exe) + + 胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号 + PowerShell 路径 + + Shell 体验 + 赞助我们 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs index 73726a78..1e7efec6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs @@ -89,6 +89,21 @@ internal sealed partial class AchievementDbService : IAchievementDbService } } + public async ValueTask OverwriteAchievementAsync(EntityAchievement achievement) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + // Delete exists one. + await appDbContext.Achievements.ExecuteDeleteWhereAsync(e => e.InnerId == achievement.InnerId).ConfigureAwait(false); + if (achievement.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED) + { + await appDbContext.Achievements.AddAndSaveAsync(achievement).ConfigureAwait(false); + } + } + } + public ObservableCollection GetAchievementArchiveCollection() { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -98,7 +113,7 @@ internal sealed partial class AchievementDbService : IAchievementDbService } } - public async ValueTask DeleteAchievementArchiveAsync(AchievementArchive archive) + public async ValueTask RemoveAchievementArchiveAsync(AchievementArchive archive) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -121,6 +136,19 @@ internal sealed partial class AchievementDbService : IAchievementDbService } } + public async ValueTask> GetAchievementListByArchiveIdAsync(Guid archiveId) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.Achievements + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId) + .ToListAsync() + .ConfigureAwait(false); + } + } + public List GetAchievementArchiveList() { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -129,4 +157,13 @@ internal sealed partial class AchievementDbService : IAchievementDbService return appDbContext.AchievementArchives.AsNoTracking().ToList(); } } + + public async ValueTask> GetAchievementArchiveListAsync() + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.AchievementArchives.AsNoTracking().ToListAsync().ConfigureAwait(false); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Archive.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Archive.cs index a2dd6936..347cbe40 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Archive.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Archive.cs @@ -74,6 +74,6 @@ internal sealed partial class AchievementService // Sync database await taskContext.SwitchToBackgroundAsync(); - await achievementDbService.DeleteAchievementArchiveAsync(archive).ConfigureAwait(false); + await achievementDbService.RemoveAchievementArchiveAsync(archive).ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Interchange.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Interchange.cs index 7ffa0fa9..85b32656 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Interchange.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.Interchange.cs @@ -50,9 +50,10 @@ internal sealed partial class AchievementService public async ValueTask ExportToUIAFAsync(AchievementArchive archive) { await taskContext.SwitchToBackgroundAsync(); - List list = achievementDbService - .GetAchievementListByArchiveId(archive.InnerId) - .SelectList(UIAFItem.From); + List entities = await achievementDbService + .GetAchievementListByArchiveIdAsync(archive.InnerId) + .ConfigureAwait(false); + List list = entities.SelectList(UIAFItem.From); return new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs index 57968a34..d7cf8deb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs @@ -22,7 +22,7 @@ internal sealed partial class AchievementStatisticsService : IAchievementStatist await taskContext.SwitchToBackgroundAsync(); List results = new(); - foreach (AchievementArchive archive in achievementDbService.GetAchievementArchiveList()) + foreach (AchievementArchive archive in await achievementDbService.GetAchievementArchiveListAsync().ConfigureAwait(false)) { int finishedCount = await achievementDbService .GetFinishedAchievementCountByArchiveIdAsync(archive.InnerId) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs index 0152f7be..ebb177df 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs @@ -9,14 +9,18 @@ namespace Snap.Hutao.Service.Achievement; internal interface IAchievementDbService { - ValueTask DeleteAchievementArchiveAsync(Model.Entity.AchievementArchive archive); + ValueTask RemoveAchievementArchiveAsync(Model.Entity.AchievementArchive archive); ObservableCollection GetAchievementArchiveCollection(); List GetAchievementArchiveList(); + ValueTask> GetAchievementArchiveListAsync(); + List GetAchievementListByArchiveId(Guid archiveId); + ValueTask> GetAchievementListByArchiveIdAsync(Guid archiveId); + Dictionary GetAchievementMapByArchiveId(Guid archiveId); ValueTask GetFinishedAchievementCountByArchiveIdAsync(Guid archiveId); @@ -24,4 +28,6 @@ internal interface IAchievementDbService ValueTask> GetLatestFinishedAchievementListByArchiveIdAsync(Guid archiveId, int take); void OverwriteAchievement(EntityAchievement achievement); + + ValueTask OverwriteAchievementAsync(EntityAchievement achievement); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs index 3a99e0ac..6b92c507 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs @@ -77,7 +77,7 @@ internal sealed partial class AvatarInfoDbBulkOperation { token.ThrowIfCancellationRequested(); string uid = userAndUid.Uid.Value; - List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); + List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); EnsureItemsAvatarIdDistinct(ref dbInfos, uid); using (IServiceScope scope = serviceProvider.CreateScope()) @@ -121,7 +121,7 @@ internal sealed partial class AvatarInfoDbBulkOperation } } - return avatarInfoDbService.GetAvatarInfoListByUid(uid); + return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); } /// @@ -134,7 +134,7 @@ internal sealed partial class AvatarInfoDbBulkOperation { token.ThrowIfCancellationRequested(); string uid = userAndUid.Uid.Value; - List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); + List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); EnsureItemsAvatarIdDistinct(ref dbInfos, uid); using (IServiceScope scope = serviceProvider.CreateScope()) @@ -173,7 +173,7 @@ internal sealed partial class AvatarInfoDbBulkOperation } } - return avatarInfoDbService.GetAvatarInfoListByUid(uid); + return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -243,7 +243,7 @@ internal sealed partial class AvatarInfoDbBulkOperation // This means that there are duplicate items. if (distinctCount < dbInfos.Count) { - avatarInfoDbService.DeleteAvatarInfoRangeByUid(uid); + avatarInfoDbService.RemoveAvatarInfoRangeByUid(uid); dbInfos = new(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs index 1ae7fb4c..8a9cc150 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs @@ -24,7 +24,20 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService } } - public void DeleteAvatarInfoRangeByUid(string uid) + public async ValueTask> GetAvatarInfoListByUidAsync(string uid) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.AvatarInfos + .AsNoTracking() + .Where(i => i.Uid == uid) + .ToListAsync() + .ConfigureAwait(false); + } + } + + public void RemoveAvatarInfoRangeByUid(string uid) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -32,4 +45,13 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService appDbContext.AvatarInfos.ExecuteDeleteWhere(i => i.Uid == uid); } } + + public async ValueTask RemoveAvatarInfoRangeByUidAsync(string uid) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.AvatarInfos.ExecuteDeleteWhereAsync(i => i.Uid == uid).ConfigureAwait(false); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs index ee1200d0..8e4a419d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs @@ -78,7 +78,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService default: { - List list = avatarInfoDbService.GetAvatarInfoListByUid(userAndUid.Uid.Value); + List list = await avatarInfoDbService.GetAvatarInfoListByUidAsync(userAndUid.Uid.Value).ConfigureAwait(false); Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false); token.ThrowIfCancellationRequested(); return new(RefreshResult.Ok, summary.Avatars.Count == 0 ? null : summary); @@ -97,7 +97,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService ?? await enkaClient.GetDataAsync(uid, token).ConfigureAwait(false); } - private async ValueTask GetSummaryCoreAsync(IEnumerable avatarInfos, CancellationToken token) + private async ValueTask GetSummaryCoreAsync(IEnumerable avatarInfos, CancellationToken token) { using (ValueStopwatch.MeasureExecution(logger)) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs index ef7f9383..a2663cee 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs @@ -7,7 +7,11 @@ namespace Snap.Hutao.Service.AvatarInfo; internal interface IAvatarInfoDbService { - void DeleteAvatarInfoRangeByUid(string uid); + void RemoveAvatarInfoRangeByUid(string uid); List GetAvatarInfoListByUid(string uid); + + ValueTask> GetAvatarInfoListByUidAsync(string uid); + + ValueTask RemoveAvatarInfoRangeByUidAsync(string uid); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs index 5364956a..c73cc773 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs @@ -66,7 +66,7 @@ internal sealed partial class CultivationDbService : ICultivationDbService } } - public async ValueTask DeleteCultivateEntryByIdAsync(Guid entryId) + public async ValueTask RemoveCultivateEntryByIdAsync(Guid entryId) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -77,15 +77,6 @@ internal sealed partial class CultivationDbService : ICultivationDbService } } - public void UpdateInventoryItem(InventoryItem item) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - appDbContext.InventoryItems.UpdateAndSave(item); - } - } - public void UpdateCultivateItem(CultivateItem item) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -95,6 +86,15 @@ internal sealed partial class CultivationDbService : ICultivationDbService } } + public async ValueTask UpdateCultivateItemAsync(CultivateItem item) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.CultivateItems.UpdateAndSaveAsync(item).ConfigureAwait(false); + } + } + public async ValueTask GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -115,7 +115,7 @@ internal sealed partial class CultivationDbService : ICultivationDbService } } - public async ValueTask DeleteCultivateItemRangeByEntryIdAsync(Guid entryId) + public async ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -144,7 +144,7 @@ internal sealed partial class CultivationDbService : ICultivationDbService } } - public async ValueTask DeleteCultivateProjectByIdAsync(Guid projectId) + public async ValueTask RemoveCultivateProjectByIdAsync(Guid projectId) { using (IServiceScope scope = serviceProvider.CreateScope()) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.Collection.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.Collection.cs index 4291d8de..39829039 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.Collection.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.Collection.cs @@ -75,6 +75,6 @@ internal sealed partial class CultivationService // Sync database await taskContext.SwitchToBackgroundAsync(); - await cultivationDbService.DeleteCultivateProjectByIdAsync(project.InnerId).ConfigureAwait(false); + await cultivationDbService.RemoveCultivateProjectByIdAsync(project.InnerId).ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index 342ed306..dbe03ca3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -8,6 +8,7 @@ using Snap.Hutao.Model.Entity.Database; using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Metadata.Item; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.Inventroy; using Snap.Hutao.ViewModel.Cultivation; using System.Collections.ObjectModel; @@ -23,6 +24,7 @@ internal sealed partial class CultivationService : ICultivationService { private readonly ScopedDbCurrent dbCurrent; private readonly ICultivationDbService cultivationDbService; + private readonly IInventoryDbService inventoryDbService; private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; @@ -140,13 +142,13 @@ internal sealed partial class CultivationService : ICultivationService public async ValueTask RemoveCultivateEntryAsync(Guid entryId) { await taskContext.SwitchToBackgroundAsync(); - await cultivationDbService.DeleteCultivateEntryByIdAsync(entryId).ConfigureAwait(false); + await cultivationDbService.RemoveCultivateEntryByIdAsync(entryId).ConfigureAwait(false); } /// public void SaveInventoryItem(InventoryItemView item) { - cultivationDbService.UpdateInventoryItem(item.Entity); + inventoryDbService.UpdateInventoryItem(item.Entity); } /// @@ -181,7 +183,7 @@ internal sealed partial class CultivationService : ICultivationService } Guid entryId = entry.InnerId; - await cultivationDbService.DeleteCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false); + await cultivationDbService.RemoveCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false); IEnumerable toAdd = items.Select(item => CultivateItem.From(entryId, item)); await cultivationDbService.AddCultivateItemRangeAsync(toAdd).ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs index 0e277b23..ffb2ed1f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs @@ -10,11 +10,11 @@ internal interface ICultivationDbService { ValueTask AddCultivateProjectAsync(CultivateProject project); - ValueTask DeleteCultivateEntryByIdAsync(Guid entryId); + ValueTask RemoveCultivateEntryByIdAsync(Guid entryId); - ValueTask DeleteCultivateItemRangeByEntryIdAsync(Guid entryId); + ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId); - ValueTask DeleteCultivateProjectByIdAsync(Guid projectId); + ValueTask RemoveCultivateProjectByIdAsync(Guid projectId); ValueTask GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId); @@ -34,5 +34,5 @@ internal interface ICultivationDbService void UpdateCultivateItem(CultivateItem item); - void UpdateInventoryItem(InventoryItem item); + ValueTask UpdateCultivateItemAsync(CultivateItem item); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs index 5829e0bb..c537e3d7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs @@ -23,6 +23,15 @@ internal sealed partial class DailyNoteDbService : IDailyNoteDbService } } + public async ValueTask ContainsUidAsync(string uid) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.DailyNotes.AsNoTracking().AnyAsync(n => n.Uid == uid).ConfigureAwait(false); + } + } + public async ValueTask AddDailyNoteEntryAsync(DailyNoteEntry entry) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -50,15 +59,6 @@ internal sealed partial class DailyNoteDbService : IDailyNoteDbService } } - public List GetDailyNoteEntryList() - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return appDbContext.DailyNotes.AsNoTracking().ToList(); - } - } - public List GetDailyNoteEntryIncludeUserList() { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -67,4 +67,13 @@ internal sealed partial class DailyNoteDbService : IDailyNoteDbService return appDbContext.DailyNotes.AsNoTracking().Include(n => n.User).ToList(); } } + + public async ValueTask> GetDailyNoteEntryIncludeUserListAsync() + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.DailyNotes.AsNoTracking().Include(n => n.User).ToListAsync().ConfigureAwait(false); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs index 968916f3..4d2cdf0b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs @@ -42,7 +42,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient entryList = dailyNoteDbService.GetDailyNoteEntryIncludeUserList(); + List entryList = await dailyNoteDbService.GetDailyNoteEntryIncludeUserListAsync().ConfigureAwait(false); entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); }); entries = new(entryList); } @@ -108,7 +108,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient ContainsUidAsync(string uid); + ValueTask DeleteDailyNoteEntryByIdAsync(Guid entryId); List GetDailyNoteEntryIncludeUserList(); - List GetDailyNoteEntryList(); + ValueTask> GetDailyNoteEntryIncludeUserListAsync(); ValueTask UpdateDailyNoteEntryAsync(DailyNoteEntry entry); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs index 9c031b2f..1e47e37a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs @@ -49,10 +49,10 @@ internal readonly struct GachaItemSaveContext // 全量刷新 if (!IsLazy) { - GachaLogDbService.DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId); + GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId); } - GachaLogDbService.AddGachaItems(ItemsToAdd); + GachaLogDbService.AddGachaItemRange(ItemsToAdd); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs index ed98e29a..dc4c3ce8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs @@ -48,7 +48,21 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } - public async ValueTask DeleteGachaArchiveByIdAsync(Guid archiveId) + public async ValueTask> GetGachaItemListByArchiveIdAsync(Guid archiveId) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.GachaItems + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId) + .OrderBy(i => i.Id) + .ToListAsync() + .ConfigureAwait(false); + } + } + + public async ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -118,6 +132,36 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService return item?.Id ?? 0L; } + public async ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType) + { + GachaItem? item = null; + + try + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + // TODO: replace with MaxBy + // https://github.com/dotnet/efcore/issues/25566 + // .MaxBy(i => i.Id); + item = await appDbContext.GachaItems + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId) + .Where(i => i.QueryType == queryType) + .OrderByDescending(i => i.Id) + .FirstOrDefaultAsync() + .ConfigureAwait(false); + } + } + catch (SqliteException ex) + { + ThrowHelper.UserdataCorrupted(SH.ServiceGachaLogEndIdUserdataCorruptedMessage, ex); + } + + return item?.Id ?? 0L; + } + public long GetOldestGachaItemIdByArchiveId(Guid archiveId) { GachaItem? item = null; @@ -139,6 +183,28 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService return item?.Id ?? long.MaxValue; } + public async ValueTask GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId) + { + GachaItem? item = null; + + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + // TODO: replace with MaxBy + // https://github.com/dotnet/efcore/issues/25566 + // .MaxBy(i => i.Id); + item = await appDbContext.GachaItems + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId) + .OrderBy(i => i.Id) + .FirstOrDefaultAsync() + .ConfigureAwait(false); + } + + return item?.Id ?? long.MaxValue; + } + public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType) { GachaItem? item = null; @@ -182,15 +248,6 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService return item?.Id ?? long.MaxValue; } - public async ValueTask AddGachaArchiveAsync(GachaArchive archive) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false); - } - } - public void AddGachaArchive(GachaArchive archive) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -200,6 +257,15 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } + public async ValueTask AddGachaArchiveAsync(GachaArchive archive) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false); + } + } + public List GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -225,6 +291,32 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } + public async ValueTask> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + return await appDbContext.GachaItems + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId) + .Where(i => i.QueryType == queryType) + .OrderByDescending(i => i.Id) + .Where(i => i.Id > endId) + + // Keep this to make SQL generates correctly + .Select(i => new Web.Hutao.GachaLog.GachaItem() + { + GachaType = i.GachaType, + QueryType = i.QueryType, + ItemId = i.ItemId, + Time = i.Time, + Id = i.Id, + }) + .ToListAsync() + .ConfigureAwait(false); + } + } + public async ValueTask GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -258,7 +350,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } - public void AddGachaItems(List items) + public void AddGachaItemRange(List items) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -267,7 +359,16 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } - public void DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId) + public async ValueTask AddGachaItemRangeAsync(List items) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.GachaItems.AddRangeAndSaveAsync(items).ConfigureAwait(false); + } + } + + public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -279,4 +380,18 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService .ExecuteDelete(); } } + + public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.GachaItems + .AsNoTracking() + .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) + .Where(i => i.Id >= endId) + .ExecuteDeleteAsync() + .ConfigureAwait(false); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs index 92a94ab4..b23e5608 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs @@ -41,7 +41,9 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer List items = new(); foreach ((GachaConfigType type, long endId) in endIds) { - List part = gachaLogDbService.GetHutaoGachaItemList(gachaArchive.InnerId, type, endId); + List part = await gachaLogDbService + .GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId) + .ConfigureAwait(false); items.AddRange(part); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index dd9ae373..e6daeaf2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -88,7 +88,7 @@ internal sealed partial class GachaLogService : IGachaLogService // Return statistics using (ValueStopwatch.MeasureExecution(logger)) { - List items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); + List items = await gachaLogDbService.GetGachaItemListByArchiveIdAsync(archive.InnerId).ConfigureAwait(false); return await gachaStatisticsFactory.CreateAsync(items, context).ConfigureAwait(false); } } @@ -102,7 +102,7 @@ internal sealed partial class GachaLogService : IGachaLogService List statistics = new(); foreach (GachaArchive archive in ArchiveCollection) { - List items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); + List items = await gachaLogDbService.GetGachaItemListByArchiveIdAsync(archive.InnerId).ConfigureAwait(false); GachaStatisticsSlim slim = await gachaStatisticsSlimFactory.CreateAsync(context, items, archive.Uid).ConfigureAwait(false); statistics.Add(slim); } @@ -150,7 +150,7 @@ internal sealed partial class GachaLogService : IGachaLogService // Sync database await taskContext.SwitchToBackgroundAsync(); - await gachaLogDbService.DeleteGachaArchiveByIdAsync(archive.InnerId).ConfigureAwait(false); + await gachaLogDbService.RemoveGachaArchiveByIdAsync(archive.InnerId).ConfigureAwait(false); // Sync cache await taskContext.SwitchToMainThreadAsync(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs index 1f55fe71..43fba695 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs @@ -13,13 +13,13 @@ internal interface IGachaLogDbService ValueTask AddGachaArchiveAsync(GachaArchive archive); - void AddGachaItems(List items); + void AddGachaItemRange(List items); ValueTask AddGachaItemsAsync(List items); - ValueTask DeleteGachaArchiveByIdAsync(Guid archiveId); + ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId); - void DeleteNewerGachaItemsByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId); + void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId); ValueTask GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token); @@ -29,6 +29,8 @@ internal interface IGachaLogDbService List GetGachaItemListByArchiveId(Guid archiveId); + ValueTask> GetGachaItemListByArchiveIdAsync(Guid archiveId); + List GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId); long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType); @@ -40,4 +42,14 @@ internal interface IGachaLogDbService long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType); ValueTask GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token); + + ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType); + + ValueTask GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId); + + ValueTask> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId); + + ValueTask AddGachaItemRangeAsync(List items); + + ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs index d0374cd7..a445785f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs @@ -24,10 +24,10 @@ internal sealed partial class UIGFExportService : IUIGFExportService public async ValueTask ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive) { await taskContext.SwitchToBackgroundAsync(); - - List list = gachaLogDbService - .GetGachaItemListByArchiveId(archive.InnerId) - .SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId))); + List entities = await gachaLogDbService + .GetGachaItemListByArchiveIdAsync(archive.InnerId) + .ConfigureAwait(false); + List list = entities.SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId))); UIGF uigf = new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs index 7c4f10ed..220d5401 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs @@ -33,15 +33,6 @@ internal sealed partial class GameDbService : IGameDbService } } - public async ValueTask UpdateGameAccountAsync(GameAccount gameAccount) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false); - } - } - public void UpdateGameAccount(GameAccount gameAccount) { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -51,7 +42,16 @@ internal sealed partial class GameDbService : IGameDbService } } - public async ValueTask DeleteGameAccountByIdAsync(Guid id) + public async ValueTask UpdateGameAccountAsync(GameAccount gameAccount) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false); + } + } + + public async ValueTask RemoveGameAccountByIdAsync(Guid id) { using (IServiceScope scope = serviceProvider.CreateScope()) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index 75e280f7..f4660afc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -386,16 +386,6 @@ internal sealed partial class GameService : IGameService gameAccounts.Remove(gameAccount); await taskContext.SwitchToBackgroundAsync(); - await gameDbService.DeleteGameAccountByIdAsync(gameAccount.InnerId).ConfigureAwait(false); - } - - private static bool LaunchSchemeMatchesExecutable(LaunchScheme launchScheme, string gameFileName) - { - return (launchScheme.IsOversea, gameFileName) switch - { - (true, GenshinImpactFileName) => true, - (false, YuanShenFileName) => true, - _ => false, - }; + await gameDbService.RemoveGameAccountByIdAsync(gameAccount.InnerId).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs index 42f50de8..0ee216f5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs @@ -10,7 +10,7 @@ internal interface IGameDbService { ValueTask AddGameAccountAsync(GameAccount gameAccount); - ValueTask DeleteGameAccountByIdAsync(Guid id); + ValueTask RemoveGameAccountByIdAsync(Guid id); ObservableCollection GetGameAccountCollection(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryDbService.cs new file mode 100644 index 00000000..74ed4288 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryDbService.cs @@ -0,0 +1,17 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Entity; + +namespace Snap.Hutao.Service.Inventroy; + +internal interface IInventoryDbService +{ + ValueTask AddInventoryItemRangeByProjectId(List items); + + ValueTask RemoveInventoryItemRangeByProjectId(Guid projectId); + + void UpdateInventoryItem(InventoryItem item); + + ValueTask UpdateInventoryItemAsync(InventoryItem item); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryService.cs new file mode 100644 index 00000000..be6fdd89 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/IInventoryService.cs @@ -0,0 +1,8 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Inventroy; + +internal interface IInventoryService +{ +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryDbService.cs new file mode 100644 index 00000000..1bd4b181 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryDbService.cs @@ -0,0 +1,61 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.EntityFrameworkCore; +using Snap.Hutao.Core.Database; +using Snap.Hutao.Model.Entity; +using Snap.Hutao.Model.Entity.Database; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Snap.Hutao.Service.Inventroy; + +[ConstructorGenerated] +[Injection(InjectAs.Singleton, typeof(IInventoryDbService))] +internal sealed partial class InventoryDbService : IInventoryDbService +{ + private readonly IServiceProvider serviceProvider; + + public async ValueTask RemoveInventoryItemRangeByProjectId(Guid projectId) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.InventoryItems + .AsNoTracking() + .Where(a => a.ProjectId == projectId && a.ItemId != 202U) // 摩拉 + .ExecuteDeleteAsync() + .ConfigureAwait(false); + } + } + + public async ValueTask AddInventoryItemRangeByProjectId(List items) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.InventoryItems.AddRangeAndSaveAsync(items).ConfigureAwait(false); + } + } + + public void UpdateInventoryItem(InventoryItem item) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + appDbContext.InventoryItems.UpdateAndSave(item); + } + } + + public async ValueTask UpdateInventoryItemAsync(InventoryItem item) + { + using (IServiceScope scope = serviceProvider.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + await appDbContext.InventoryItems.UpdateAndSaveAsync(item).ConfigureAwait(false); + } + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryService.cs new file mode 100644 index 00000000..7904038d --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventroy/InventoryService.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Inventroy; + +[Injection(InjectAs.Transient)] +internal sealed class InventoryService : IInventoryService +{ +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs index 7e5833e2..2cdd5ef4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs @@ -48,4 +48,4 @@ internal sealed partial class SpiralAbyssRecordDbService : ISpiralAbyssRecordDbS await appDbContext.SpiralAbysses.AddAndSaveAsync(entry).ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs index 82274eb3..b0256188 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs @@ -9,7 +9,7 @@ internal interface IUserDbService ValueTask DeleteUserByIdAsync(Guid id); - ValueTask DeleteUsersAsync(); + ValueTask RemoveUsersAsync(); ValueTask> GetUserListAsync(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs index a407fac6..c3abc869 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs @@ -49,7 +49,7 @@ internal sealed partial class UserDbService : IUserDbService } } - public async ValueTask DeleteUsersAsync() + public async ValueTask RemoveUsersAsync() { using (IServiceScope scope = serviceProvider.CreateScope()) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs index 4abe839d..06a232e6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs @@ -61,7 +61,7 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe public async ValueTask UnsafeRemoveUsersAsync() { await taskContext.SwitchToBackgroundAsync(); - await userDbService.DeleteUsersAsync().ConfigureAwait(false); + await userDbService.RemoveUsersAsync().ConfigureAwait(false); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 7b191905..1e7a8fb3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -79,6 +79,7 @@ + @@ -206,6 +207,7 @@ + @@ -239,12 +241,12 @@ - - - - - - + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/CardReference.cs b/src/Snap.Hutao/Snap.Hutao/View/Card/CardReference.cs new file mode 100644 index 00000000..2335bf3e --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Card/CardReference.cs @@ -0,0 +1,11 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml.Controls; + +namespace Snap.Hutao.View.Card; + +internal sealed class CardReference +{ + public Button? Card { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml index 9403b285..e017c747 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml @@ -124,7 +124,7 @@ + Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}"> diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml index 9887f549..434094f1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml @@ -76,11 +76,7 @@ Margin="2,6,3,6" DisplayMemberPath="Name" ItemsSource="{Binding Archives, Mode=OneWay}" - SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"> - - - - + SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/> - - + + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + - - - - - + + + Visibility="{Binding ShouldShowTimeDescription, Converter={StaticResource BoolToVisibilityConverter}}"> + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - + - + - - - - - - - - + Visibility="{Binding Cards.Count, Converter={StaticResource Int32ToVisibilityConverter}}"> + + + + + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml index 012ee9ae..e1c644d2 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml @@ -66,11 +66,7 @@ Margin="6,6,6,6" DisplayMemberPath="Name" ItemsSource="{Binding Projects}" - SelectedItem="{Binding SelectedProject, Mode=TwoWay}"> - - - - + SelectedItem="{Binding SelectedProject, Mode=TwoWay}"/> - - - - + SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/> diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml index c525e592..0f78a8bc 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml @@ -23,9 +23,9 @@ - + Source="ms-appx:///Resource/BlurBackground.png" + Stretch="Fill"/> + @@ -91,6 +91,8 @@ Description="{Binding HutaoOptions.WebView2Version}" Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}" HeaderIcon="{shcm:FontIcon Glyph=}"/> + + + + + + + + + + + + + + + + + + + + - + IsClickEnabled="True"> + + + + + + + + IsClickEnabled="True"> + + + + + + + ? hutaoAnnouncements; + private List? cards; /// /// 公告 @@ -43,8 +46,11 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel /// public string GreetingText { get => greetingText; set => SetProperty(ref greetingText, value); } + public List? Cards { get => cards; set => SetProperty(ref cards, value); } + protected override ValueTask InitializeUIAsync() { + InitializeDashboard(); InitializeInGameAnnouncementAsync().SafeForget(); InitializeHutaoAnnouncementAsync().SafeForget(); UpdateGreetingText(); @@ -105,4 +111,31 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel } } } + + private void InitializeDashboard() + { + List result = new(); + + if (LocalSetting.Get(SettingKeys.IsHomeCardLaunchGamePresented, true)) + { + result.Add(new() { Card = new LaunchGameCard() }); + } + + if (LocalSetting.Get(SettingKeys.IsHomeCardGachaStatisticsPresented, true)) + { + result.Add(new() { Card = new GachaStatisticsCard() }); + } + + if (LocalSetting.Get(SettingKeys.IsHomeCardAchievementPresented, true)) + { + result.Add(new() { Card = new AchievementCard() }); + } + + if (LocalSetting.Get(SettingKeys.IsHomeCardDailyNotePresented, true)) + { + result.Add(new() { Card = new DailyNoteCard() }); + } + + Cards = result; + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/HomeCardOptions.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/HomeCardOptions.cs new file mode 100644 index 00000000..4aa00d26 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/HomeCardOptions.cs @@ -0,0 +1,33 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Setting; + +namespace Snap.Hutao.ViewModel; + +internal sealed class HomeCardOptions +{ + public bool IsHomeCardLaunchGamePresented + { + get => LocalSetting.Get(SettingKeys.IsHomeCardLaunchGamePresented, true); + set => LocalSetting.Set(SettingKeys.IsHomeCardLaunchGamePresented, value); + } + + public bool IsHomeCardGachaStatisticsPresented + { + get => LocalSetting.Get(SettingKeys.IsHomeCardGachaStatisticsPresented, true); + set => LocalSetting.Set(SettingKeys.IsHomeCardGachaStatisticsPresented, value); + } + + public bool IsHomeCardAchievementPresented + { + get => LocalSetting.Get(SettingKeys.IsHomeCardAchievementPresented, true); + set => LocalSetting.Set(SettingKeys.IsHomeCardAchievementPresented, value); + } + + public bool IsHomeCardDailyNotePresented + { + get => LocalSetting.Get(SettingKeys.IsHomeCardDailyNotePresented, true); + set => LocalSetting.Set(SettingKeys.IsHomeCardDailyNotePresented, value); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs index 896123c8..e507753a 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs @@ -37,6 +37,8 @@ namespace Snap.Hutao.ViewModel; [Injection(InjectAs.Scoped)] internal sealed partial class SettingViewModel : Abstraction.ViewModel { + private readonly HomeCardOptions homeCardOptions = new(); + private readonly IContentDialogFactory contentDialogFactory; private readonly IGameLocatorFactory gameLocatorFactory; private readonly INavigationService navigationService; @@ -68,6 +70,8 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel /// public HutaoUserOptions UserOptions { get => hutaoUserOptions; } + public HomeCardOptions HomeCardOptions { get => homeCardOptions; } + /// /// 选中的背景类型 ///