mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
improve db layer & homecard experience
This commit is contained in:
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// AppTitleBar Workaround
|
||||
/// https://github.com/microsoft/microsoft-ui-xaml/issues/7756
|
||||
/// </summary>
|
||||
internal sealed class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase<ComboBox>
|
||||
{
|
||||
private readonly IMessenger messenger;
|
||||
private readonly EventHandler<object> dropDownOpenedHandler;
|
||||
private readonly EventHandler<object> dropDownClosedHandler;
|
||||
|
||||
/// <summary>
|
||||
/// AppTitleBar Workaround
|
||||
/// </summary>
|
||||
public ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior()
|
||||
{
|
||||
messenger = Ioc.Default.GetRequiredService<IMessenger>();
|
||||
dropDownOpenedHandler = OnDropDownOpened;
|
||||
dropDownClosedHandler = OnDropDownClosed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool Initialize()
|
||||
{
|
||||
AssociatedObject.DropDownOpened += dropDownOpenedHandler;
|
||||
AssociatedObject.DropDownClosed += dropDownClosedHandler;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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<Window> reference = new(default!);
|
||||
|
||||
[SuppressMessage("", "SH007")]
|
||||
public Window Window
|
||||
{
|
||||
get
|
||||
{
|
||||
reference.TryGetTarget(out Window? window);
|
||||
return window!;
|
||||
}
|
||||
set => reference.SetTarget(value);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 功能
|
||||
/// </summary>
|
||||
internal sealed class Feature : ObservableObject
|
||||
{
|
||||
private readonly string displayName;
|
||||
private readonly string description;
|
||||
private readonly string settingKey;
|
||||
private readonly bool defaultValue;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的功能
|
||||
/// </summary>
|
||||
/// <param name="displayName">显示名称</param>
|
||||
/// <param name="description">描述</param>
|
||||
/// <param name="settingKey">键</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
public Feature(string displayName, string description, string settingKey, bool defaultValue)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
this.description = description;
|
||||
this.settingKey = settingKey;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get => displayName; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get => description; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public bool Value
|
||||
{
|
||||
get => LocalSetting.Get(settingKey, defaultValue);
|
||||
set
|
||||
{
|
||||
LocalSetting.Set(settingKey, value);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections;
|
||||
|
||||
namespace Snap.Hutao.Core.Setting;
|
||||
|
||||
/// <summary>
|
||||
/// 功能选项
|
||||
/// </summary>
|
||||
internal sealed class FeatureOptions : IReadOnlyCollection<Feature>
|
||||
{
|
||||
/// <summary>
|
||||
/// 启用实时便笺无感验证
|
||||
/// </summary>
|
||||
public Feature IsDailyNoteSilentVerificationEnabled { get; } = new(
|
||||
"IsDailyNoteSilentVerificationEnabled", "启用实时便笺无感验证", "IsDailyNoteSilentVerificationEnabled", true);
|
||||
|
||||
/// <summary>
|
||||
/// 元数据检查是否忽略
|
||||
/// </summary>
|
||||
public Feature IsMetadataUpdateCheckSuppressed { get; } = new(
|
||||
"IsMetadataUpdateCheckSuppressed", "禁用元数据更新检查", "IsMetadataUpdateCheckSuppressed", false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count { get => 2; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<Feature> GetEnumerator()
|
||||
{
|
||||
// TODO: Use source generator
|
||||
yield return IsDailyNoteSilentVerificationEnabled;
|
||||
yield return IsMetadataUpdateCheckSuppressed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ internal sealed class CalculableWeapon
|
||||
IMappingFrom<CalculableWeapon, Weapon>,
|
||||
IMappingFrom<CalculableWeapon, WeaponView>
|
||||
{
|
||||
private uint levelCurrent;
|
||||
private uint levelTarget;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算武器
|
||||
/// </summary>
|
||||
|
||||
@@ -13,32 +13,8 @@ internal sealed class UIIFItem
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("itemId")]
|
||||
public int ItemId { get; set; }
|
||||
public uint ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("count")]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// Reliquary/Weapon
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int? Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副属性列表
|
||||
/// Reliquary
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropIdList")]
|
||||
public List<int>? AppendPropIdList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 精炼等级 0-4
|
||||
/// Weapon
|
||||
/// </summary>
|
||||
[JsonPropertyName("promoteLevel")]
|
||||
public int? PromoteLevel { get; set; }
|
||||
[JsonPropertyName("material")]
|
||||
public UIIFMaterial Material { get; set; } = default!;
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
BIN
src/Snap.Hutao/Snap.Hutao/Resource/BlurBackground.png
Normal file
BIN
src/Snap.Hutao/Snap.Hutao/Resource/BlurBackground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
@@ -5245,7 +5245,7 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 在桌面上创建默认以管理员方式启动的快捷方式,更新后需要重新创建 的本地化字符串。
|
||||
/// 查找类似 在桌面上创建默认以管理员方式启动的快捷方式 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingCreateDesktopShortcutDescription {
|
||||
get {
|
||||
@@ -5469,6 +5469,87 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 管理主页仪表板中的卡片 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 主页卡片 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 成就管理 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardItemAchievementHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardItemAchievementHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 实时便笺 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardItemDailyNoteHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardItemDailyNoteHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 祈愿记录 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardItemgachaStatisticsHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardItemgachaStatisticsHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 启动游戏 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeCardItemLaunchGameHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeCardItemLaunchGameHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 隐藏 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingHomeCardOff {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingHomeCardOff", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 显示 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingHomeCardOn {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingHomeCardOn", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 主页 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewpageSettingHomeHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewpageSettingHomeHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 胡桃账号 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -5577,6 +5658,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingSetPowerShellDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingSetPowerShellDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 PowerShell 路径 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -5586,6 +5676,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Shell 体验 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingShellExperienceHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingShellExperienceHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 赞助我们 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1902,7 +1902,7 @@
|
||||
<value>创建</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCreateDesktopShortcutDescription" xml:space="preserve">
|
||||
<value>在桌面上创建默认以管理员方式启动的快捷方式,更新后需要重新创建</value>
|
||||
<value>在桌面上创建默认以管理员方式启动的快捷方式</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCreateDesktopShortcutHeader" xml:space="preserve">
|
||||
<value>创建快捷方式</value>
|
||||
@@ -1976,6 +1976,33 @@
|
||||
<data name="ViewPageSettingGeetestVerificationHeader" xml:space="preserve">
|
||||
<value>无感验证</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardDescription" xml:space="preserve">
|
||||
<value>管理主页仪表板中的卡片</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardHeader" xml:space="preserve">
|
||||
<value>主页卡片</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemAchievementHeader" xml:space="preserve">
|
||||
<value>成就管理</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
|
||||
<value>实时便笺</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
|
||||
<value>祈愿记录</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemLaunchGameHeader" xml:space="preserve">
|
||||
<value>启动游戏</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHomeCardOff" xml:space="preserve">
|
||||
<value>隐藏</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHomeCardOn" xml:space="preserve">
|
||||
<value>显示</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeHeader" xml:space="preserve">
|
||||
<value>主页</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoPassportHeader" xml:space="preserve">
|
||||
<value>胡桃账号</value>
|
||||
</data>
|
||||
@@ -2012,9 +2039,15 @@
|
||||
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
|
||||
<value>设置游戏路径时,请选择游戏本体(YuanShen.exe 或 GenshinImpact.exe)而不是启动器(launcher.exe)</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetPowerShellDescription" xml:space="preserve">
|
||||
<value>胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
|
||||
<value>PowerShell 路径</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
|
||||
<value>Shell 体验</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
|
||||
<value>赞助我们</value>
|
||||
</data>
|
||||
|
||||
@@ -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<AppDbContext>();
|
||||
|
||||
// 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<AchievementArchive> 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<List<EntityAchievement>> GetAchievementListByArchiveIdAsync(Guid archiveId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.Achievements
|
||||
.AsNoTracking()
|
||||
.Where(i => i.ArchiveId == archiveId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public List<AchievementArchive> GetAchievementArchiveList()
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
@@ -129,4 +157,13 @@ internal sealed partial class AchievementDbService : IAchievementDbService
|
||||
return appDbContext.AchievementArchives.AsNoTracking().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<List<AchievementArchive>> GetAchievementArchiveListAsync()
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.AchievementArchives.AsNoTracking().ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,10 @@ internal sealed partial class AchievementService
|
||||
public async ValueTask<UIAF> ExportToUIAFAsync(AchievementArchive archive)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
List<UIAFItem> list = achievementDbService
|
||||
.GetAchievementListByArchiveId(archive.InnerId)
|
||||
.SelectList(UIAFItem.From);
|
||||
List<EntityAchievement> entities = await achievementDbService
|
||||
.GetAchievementListByArchiveIdAsync(archive.InnerId)
|
||||
.ConfigureAwait(false);
|
||||
List<UIAFItem> list = entities.SelectList(UIAFItem.From);
|
||||
|
||||
return new()
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ internal sealed partial class AchievementStatisticsService : IAchievementStatist
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
List<AchievementStatistics> results = new();
|
||||
foreach (AchievementArchive archive in achievementDbService.GetAchievementArchiveList())
|
||||
foreach (AchievementArchive archive in await achievementDbService.GetAchievementArchiveListAsync().ConfigureAwait(false))
|
||||
{
|
||||
int finishedCount = await achievementDbService
|
||||
.GetFinishedAchievementCountByArchiveIdAsync(archive.InnerId)
|
||||
|
||||
@@ -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<Model.Entity.AchievementArchive> GetAchievementArchiveCollection();
|
||||
|
||||
List<Model.Entity.AchievementArchive> GetAchievementArchiveList();
|
||||
|
||||
ValueTask<List<Model.Entity.AchievementArchive>> GetAchievementArchiveListAsync();
|
||||
|
||||
List<EntityAchievement> GetAchievementListByArchiveId(Guid archiveId);
|
||||
|
||||
ValueTask<List<EntityAchievement>> GetAchievementListByArchiveIdAsync(Guid archiveId);
|
||||
|
||||
Dictionary<AchievementId, EntityAchievement> GetAchievementMapByArchiveId(Guid archiveId);
|
||||
|
||||
ValueTask<int> GetFinishedAchievementCountByArchiveIdAsync(Guid archiveId);
|
||||
@@ -24,4 +28,6 @@ internal interface IAchievementDbService
|
||||
ValueTask<List<EntityAchievement>> GetLatestFinishedAchievementListByArchiveIdAsync(Guid archiveId, int take);
|
||||
|
||||
void OverwriteAchievement(EntityAchievement achievement);
|
||||
|
||||
ValueTask OverwriteAchievementAsync(EntityAchievement achievement);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
string uid = userAndUid.Uid.Value;
|
||||
List<EntityAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||
List<EntityAvatarInfo> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -134,7 +134,7 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
string uid = userAndUid.Uid.Value;
|
||||
List<EntityAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||
List<EntityAvatarInfo> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,20 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAvatarInfoRangeByUid(string uid)
|
||||
public async ValueTask<List<EntityAvatarInfo>> GetAvatarInfoListByUidAsync(string uid)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
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<AppDbContext>();
|
||||
await appDbContext.AvatarInfos.ExecuteDeleteWhereAsync(i => i.Uid == uid).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService
|
||||
|
||||
default:
|
||||
{
|
||||
List<EntityAvatarInfo> list = avatarInfoDbService.GetAvatarInfoListByUid(userAndUid.Uid.Value);
|
||||
List<EntityAvatarInfo> 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<Summary> GetSummaryCoreAsync(IEnumerable<Model.Entity.AvatarInfo> avatarInfos, CancellationToken token)
|
||||
private async ValueTask<Summary> GetSummaryCoreAsync(IEnumerable<EntityAvatarInfo> avatarInfos, CancellationToken token)
|
||||
{
|
||||
using (ValueStopwatch.MeasureExecution(logger))
|
||||
{
|
||||
|
||||
@@ -7,7 +7,11 @@ namespace Snap.Hutao.Service.AvatarInfo;
|
||||
|
||||
internal interface IAvatarInfoDbService
|
||||
{
|
||||
void DeleteAvatarInfoRangeByUid(string uid);
|
||||
void RemoveAvatarInfoRangeByUid(string uid);
|
||||
|
||||
List<EntityAvatarInfo> GetAvatarInfoListByUid(string uid);
|
||||
|
||||
ValueTask<List<EntityAvatarInfo>> GetAvatarInfoListByUidAsync(string uid);
|
||||
|
||||
ValueTask RemoveAvatarInfoRangeByUidAsync(string uid);
|
||||
}
|
||||
@@ -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>();
|
||||
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<AppDbContext>();
|
||||
await appDbContext.CultivateItems.UpdateAndSaveAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<CultivateEntry?> 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())
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CultivateProject, Message.CultivateProjectChangedMessage> 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);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveInventoryItem(InventoryItemView item)
|
||||
{
|
||||
cultivationDbService.UpdateInventoryItem(item.Entity);
|
||||
inventoryDbService.UpdateInventoryItem(item.Entity);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -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<CultivateItem> toAdd = items.Select(item => CultivateItem.From(entryId, item));
|
||||
await cultivationDbService.AddCultivateItemRangeAsync(toAdd).ConfigureAwait(false);
|
||||
|
||||
@@ -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<CultivateEntry?> GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId);
|
||||
|
||||
@@ -34,5 +34,5 @@ internal interface ICultivationDbService
|
||||
|
||||
void UpdateCultivateItem(CultivateItem item);
|
||||
|
||||
void UpdateInventoryItem(InventoryItem item);
|
||||
ValueTask UpdateCultivateItemAsync(CultivateItem item);
|
||||
}
|
||||
@@ -23,6 +23,15 @@ internal sealed partial class DailyNoteDbService : IDailyNoteDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ContainsUidAsync(string uid)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
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<DailyNoteEntry> GetDailyNoteEntryList()
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return appDbContext.DailyNotes.AsNoTracking().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<DailyNoteEntry> 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<List<DailyNoteEntry>> GetDailyNoteEntryIncludeUserListAsync()
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.DailyNotes.AsNoTracking().Include(n => n.User).ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
||||
{
|
||||
string roleUid = userAndUid.Uid.Value;
|
||||
|
||||
if (!dailyNoteDbService.ContainsUid(roleUid))
|
||||
if (!await dailyNoteDbService.ContainsUidAsync(roleUid).ConfigureAwait(false))
|
||||
{
|
||||
DailyNoteEntry newEntry = DailyNoteEntry.From(userAndUid);
|
||||
|
||||
@@ -75,7 +75,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
||||
await userService.GetRoleCollectionAsync().ConfigureAwait(false);
|
||||
await RefreshDailyNotesCoreAsync(forceRefresh).ConfigureAwait(false);
|
||||
|
||||
List<DailyNoteEntry> entryList = dailyNoteDbService.GetDailyNoteEntryIncludeUserList();
|
||||
List<DailyNoteEntry> 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<U
|
||||
|
||||
private async ValueTask RefreshDailyNotesCoreAsync(bool forceRefresh)
|
||||
{
|
||||
foreach (DailyNoteEntry entry in dailyNoteDbService.GetDailyNoteEntryIncludeUserList())
|
||||
foreach (DailyNoteEntry entry in await dailyNoteDbService.GetDailyNoteEntryIncludeUserListAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (!forceRefresh && entry.DailyNote is not null)
|
||||
{
|
||||
|
||||
@@ -11,11 +11,13 @@ internal interface IDailyNoteDbService
|
||||
|
||||
bool ContainsUid(string uid);
|
||||
|
||||
ValueTask<bool> ContainsUidAsync(string uid);
|
||||
|
||||
ValueTask DeleteDailyNoteEntryByIdAsync(Guid entryId);
|
||||
|
||||
List<DailyNoteEntry> GetDailyNoteEntryIncludeUserList();
|
||||
|
||||
List<DailyNoteEntry> GetDailyNoteEntryList();
|
||||
ValueTask<List<DailyNoteEntry>> GetDailyNoteEntryIncludeUserListAsync();
|
||||
|
||||
ValueTask UpdateDailyNoteEntryAsync(DailyNoteEntry entry);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,21 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DeleteGachaArchiveByIdAsync(Guid archiveId)
|
||||
public async ValueTask<List<GachaItem>> GetGachaItemListByArchiveIdAsync(Guid archiveId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
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<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
// 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<long> GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
// 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<AppDbContext>();
|
||||
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<AppDbContext>();
|
||||
await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Web.Hutao.GachaLog.GachaItem> 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<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
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<GachaArchive?> GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
@@ -258,7 +350,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public void AddGachaItems(List<GachaItem> items)
|
||||
public void AddGachaItemRange(List<GachaItem> 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<GachaItem> items)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
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<AppDbContext>();
|
||||
await appDbContext.GachaItems
|
||||
.AsNoTracking()
|
||||
.Where(i => i.ArchiveId == archiveId && i.QueryType == queryType)
|
||||
.Where(i => i.Id >= endId)
|
||||
.ExecuteDeleteAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,9 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
List<Web.Hutao.GachaLog.GachaItem> items = new();
|
||||
foreach ((GachaConfigType type, long endId) in endIds)
|
||||
{
|
||||
List<Web.Hutao.GachaLog.GachaItem> part = gachaLogDbService.GetHutaoGachaItemList(gachaArchive.InnerId, type, endId);
|
||||
List<Web.Hutao.GachaLog.GachaItem> part = await gachaLogDbService
|
||||
.GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId)
|
||||
.ConfigureAwait(false);
|
||||
items.AddRange(part);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ internal sealed partial class GachaLogService : IGachaLogService
|
||||
// Return statistics
|
||||
using (ValueStopwatch.MeasureExecution(logger))
|
||||
{
|
||||
List<GachaItem> items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId);
|
||||
List<GachaItem> 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<GachaStatisticsSlim> statistics = new();
|
||||
foreach (GachaArchive archive in ArchiveCollection)
|
||||
{
|
||||
List<GachaItem> items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId);
|
||||
List<GachaItem> 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();
|
||||
|
||||
@@ -13,13 +13,13 @@ internal interface IGachaLogDbService
|
||||
|
||||
ValueTask AddGachaArchiveAsync(GachaArchive archive);
|
||||
|
||||
void AddGachaItems(List<GachaItem> items);
|
||||
void AddGachaItemRange(List<GachaItem> items);
|
||||
|
||||
ValueTask AddGachaItemsAsync(List<GachaItem> 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<GachaArchive?> GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token);
|
||||
|
||||
@@ -29,6 +29,8 @@ internal interface IGachaLogDbService
|
||||
|
||||
List<GachaItem> GetGachaItemListByArchiveId(Guid archiveId);
|
||||
|
||||
ValueTask<List<GachaItem>> GetGachaItemListByArchiveIdAsync(Guid archiveId);
|
||||
|
||||
List<Web.Hutao.GachaLog.GachaItem> 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<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType);
|
||||
|
||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId);
|
||||
|
||||
ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
|
||||
ValueTask AddGachaItemRangeAsync(List<GachaItem> items);
|
||||
|
||||
ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
}
|
||||
@@ -24,10 +24,10 @@ internal sealed partial class UIGFExportService : IUIGFExportService
|
||||
public async ValueTask<UIGF> ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
List<UIGFItem> list = gachaLogDbService
|
||||
.GetGachaItemListByArchiveId(archive.InnerId)
|
||||
.SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId)));
|
||||
List<GachaItem> entities = await gachaLogDbService
|
||||
.GetGachaItemListByArchiveIdAsync(archive.InnerId)
|
||||
.ConfigureAwait(false);
|
||||
List<UIGFItem> list = entities.SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId)));
|
||||
|
||||
UIGF uigf = new()
|
||||
{
|
||||
|
||||
@@ -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<AppDbContext>();
|
||||
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<AppDbContext>();
|
||||
await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveGameAccountByIdAsync(Guid id)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ internal interface IGameDbService
|
||||
{
|
||||
ValueTask AddGameAccountAsync(GameAccount gameAccount);
|
||||
|
||||
ValueTask DeleteGameAccountByIdAsync(Guid id);
|
||||
ValueTask RemoveGameAccountByIdAsync(Guid id);
|
||||
|
||||
ObservableCollection<GameAccount> GetGameAccountCollection();
|
||||
|
||||
|
||||
@@ -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<InventoryItem> items);
|
||||
|
||||
ValueTask RemoveInventoryItemRangeByProjectId(Guid projectId);
|
||||
|
||||
void UpdateInventoryItem(InventoryItem item);
|
||||
|
||||
ValueTask UpdateInventoryItemAsync(InventoryItem item);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Inventroy;
|
||||
|
||||
internal interface IInventoryService
|
||||
{
|
||||
}
|
||||
@@ -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<AppDbContext>();
|
||||
await appDbContext.InventoryItems
|
||||
.AsNoTracking()
|
||||
.Where(a => a.ProjectId == projectId && a.ItemId != 202U) // 摩拉
|
||||
.ExecuteDeleteAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask AddInventoryItemRangeByProjectId(List<InventoryItem> items)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.InventoryItems.AddRangeAndSaveAsync(items).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateInventoryItem(InventoryItem item)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
appDbContext.InventoryItems.UpdateAndSave(item);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask UpdateInventoryItemAsync(InventoryItem item)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.InventoryItems.UpdateAndSaveAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -9,7 +9,7 @@ internal interface IUserDbService
|
||||
|
||||
ValueTask DeleteUserByIdAsync(Guid id);
|
||||
|
||||
ValueTask DeleteUsersAsync();
|
||||
ValueTask RemoveUsersAsync();
|
||||
|
||||
ValueTask<List<Model.Entity.User>> GetUserListAsync();
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ internal sealed partial class UserDbService : IUserDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DeleteUsersAsync()
|
||||
public async ValueTask RemoveUsersAsync()
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<None Remove="LaunchGameWindow.xaml" />
|
||||
<None Remove="NativeMethods.json" />
|
||||
<None Remove="NativeMethods.txt" />
|
||||
<None Remove="Resource\BlurBackground.png" />
|
||||
<None Remove="Resource\Font\CascadiaMono.ttf" />
|
||||
<None Remove="Resource\Font\MiSans-Regular.ttf" />
|
||||
<None Remove="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||
@@ -206,6 +207,7 @@
|
||||
|
||||
<!-- Resources Files -->
|
||||
<ItemGroup>
|
||||
<Content Include="Resource\BlurBackground.png" />
|
||||
<Content Include="Resource\Font\CascadiaMono.ttf" />
|
||||
<Content Include="Resource\Font\MiSans-Regular.ttf" />
|
||||
<Content Include="Resource\HutaoIconSourceTransparentBackgroundGradient1.png" />
|
||||
@@ -239,12 +241,12 @@
|
||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.TokenView" Version="0.1.230809" />
|
||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.TransitionHelper" Version="0.1.230809" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2-build.1" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.HeaderedControls" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.230828-rc" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.HeaderedControls" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.230907" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Core" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
|
||||
|
||||
11
src/Snap.Hutao/Snap.Hutao/View/Card/CardReference.cs
Normal file
11
src/Snap.Hutao/Snap.Hutao/View/Card/CardReference.cs
Normal file
@@ -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; }
|
||||
}
|
||||
@@ -124,7 +124,7 @@
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{Binding Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8" DataContext="{x:Bind Weapon}">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
||||
@@ -76,11 +76,7 @@
|
||||
Margin="2,6,3,6"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Archives, Mode=OneWay}"
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/>
|
||||
</AppBarElementContainer>
|
||||
<AppBarButton
|
||||
Command="{Binding AddArchiveCommand}"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
xmlns:cwa="using:CommunityToolkit.WinUI.Animations"
|
||||
xmlns:cwb="using:CommunityToolkit.WinUI.Behaviors"
|
||||
xmlns:cwu="using:CommunityToolkit.WinUI.UI"
|
||||
xmlns:cwucont="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
@@ -15,7 +14,6 @@
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvca="using:Snap.Hutao.View.Card"
|
||||
xmlns:shvco="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvh="using:Snap.Hutao.ViewModel.Home"
|
||||
d:DataContext="{d:DesignInstance shvh:AnnouncementViewModel}"
|
||||
@@ -29,140 +27,147 @@
|
||||
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
||||
|
||||
<DataTemplate x:Key="AnnouncementTemplate">
|
||||
<cwucont:AdaptiveGridView
|
||||
Margin="16,16,0,-4"
|
||||
<ItemsView
|
||||
Margin="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
cwa:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="{StaticResource AdaptiveGridViewDesiredWidth}"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
IsItemInvokedEnabled="False"
|
||||
ItemsSource="{Binding List}"
|
||||
SelectionMode="None">
|
||||
<cwucont:AdaptiveGridView.ItemTemplate>
|
||||
<ItemsView.Layout>
|
||||
<UniformGridLayout
|
||||
ItemsJustification="Start"
|
||||
ItemsStretch="Fill"
|
||||
MinColumnSpacing="12"
|
||||
MinItemWidth="300"
|
||||
MinRowSpacing="12"/>
|
||||
</ItemsView.Layout>
|
||||
<ItemsView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border cwu:UIElementExtensions.ClipToBounds="True" Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Image Layer -->
|
||||
<Border cwu:UIElementExtensions.ClipToBounds="True">
|
||||
<Border VerticalAlignment="Top" cwu:VisualExtensions.NormalizedCenterPoint="0.5">
|
||||
<shci:CachedImage Source="{Binding Banner}" Stretch="UniformToFill"/>
|
||||
<ItemContainer>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Image Layer -->
|
||||
<Border cwu:UIElementExtensions.ClipToBounds="True">
|
||||
<Border VerticalAlignment="Top" cwu:VisualExtensions.NormalizedCenterPoint="0.5">
|
||||
<shci:CachedImage Source="{Binding Banner}" Stretch="UniformToFill"/>
|
||||
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:AutoHeightBehavior TargetHeight="390" TargetWidth="1080"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<cwa:Explicit.Animations>
|
||||
<cwa:AnimationSet x:Name="ImageZoomInAnimation">
|
||||
<shca:ImageZoomInAnimation/>
|
||||
</cwa:AnimationSet>
|
||||
<cwa:AnimationSet x:Name="ImageZoomOutAnimation">
|
||||
<shca:ImageZoomOutAnimation/>
|
||||
</cwa:AnimationSet>
|
||||
</cwa:Explicit.Animations>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:AutoHeightBehavior TargetHeight="390" TargetWidth="1080"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<cwa:Explicit.Animations>
|
||||
<cwa:AnimationSet x:Name="ImageZoomInAnimation">
|
||||
<shca:ImageZoomInAnimation/>
|
||||
</cwa:AnimationSet>
|
||||
<cwa:AnimationSet x:Name="ImageZoomOutAnimation">
|
||||
<shca:ImageZoomOutAnimation/>
|
||||
</cwa:AnimationSet>
|
||||
</cwa:Explicit.Animations>
|
||||
</Border>
|
||||
</Border>
|
||||
</Border>
|
||||
<!-- Time Description -->
|
||||
<Grid Grid.Row="0">
|
||||
<Border
|
||||
Height="24"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Visibility="{Binding ShouldShowTimeDescription, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ProgressBar
|
||||
MinHeight="2"
|
||||
<!-- Time Description -->
|
||||
<Grid Grid.Row="0">
|
||||
<Border
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Background="Transparent"
|
||||
CornerRadius="0"
|
||||
Maximum="1"
|
||||
Value="{Binding TimePercent, Mode=OneWay}"/>
|
||||
Visibility="{Binding ShouldShowTimeDescription, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ProgressBar
|
||||
MinHeight="2"
|
||||
VerticalAlignment="Bottom"
|
||||
Background="Transparent"
|
||||
CornerRadius="0"
|
||||
Maximum="1"
|
||||
Value="{Binding TimePercent, Mode=OneWay}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<!-- General Description -->
|
||||
<Border Grid.Row="1" CornerRadius="{StaticResource CompatCornerRadiusBottom}">
|
||||
<StackPanel Margin="4" VerticalAlignment="Bottom">
|
||||
<TextBlock
|
||||
Margin="4,6,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Subtitle}"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="4,6,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{Binding Title}"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Margin="4,4,0,4"
|
||||
FontSize="10"
|
||||
Opacity="0.4"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding TimeFormatted}"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="4,4,4,4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
FontSize="10"
|
||||
Opacity="0.8"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding TimeDescription}"
|
||||
Visibility="{Binding ShouldShowTimeDescription, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
<!-- General Description -->
|
||||
<Border Grid.Row="1" CornerRadius="{StaticResource CompatCornerRadiusBottom}">
|
||||
<StackPanel Margin="4" VerticalAlignment="Bottom">
|
||||
<TextBlock
|
||||
Margin="4,6,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Subtitle}"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="4,6,0,0"
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{Binding Title}"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Margin="4,4,0,4"
|
||||
FontSize="10"
|
||||
Opacity="0.4"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding TimeFormatted}"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="4,4,4,4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
FontSize="10"
|
||||
Opacity="0.8"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding TimeDescription}"
|
||||
Visibility="{Binding ShouldShowTimeDescription, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
<FlyoutBase.AttachedFlyout>
|
||||
<Flyout LightDismissOverlayMode="On" Placement="Full">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="CornerRadius" Value="0"/>
|
||||
<Setter Property="MaxWidth" Value="640"/>
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<shvco:AnnouncementContentViewer Announcement="{Binding}"/>
|
||||
</Flyout>
|
||||
</FlyoutBase.AttachedFlyout>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="Tapped">
|
||||
<shcb:OpenAttachedFlyoutAction/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<cwb:StartAnimationAction Animation="{Binding ElementName=ImageZoomInAnimation}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<cwb:StartAnimationAction Animation="{Binding ElementName=ImageZoomOutAnimation}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Border>
|
||||
<FlyoutBase.AttachedFlyout>
|
||||
<Flyout LightDismissOverlayMode="On" Placement="Full">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="CornerRadius" Value="0"/>
|
||||
<Setter Property="MaxWidth" Value="640"/>
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<shvco:AnnouncementContentViewer Announcement="{Binding}"/>
|
||||
</Flyout>
|
||||
</FlyoutBase.AttachedFlyout>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="Tapped">
|
||||
<shcb:OpenAttachedFlyoutAction/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<cwb:StartAnimationAction Animation="{Binding ElementName=ImageZoomInAnimation}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<cwb:StartAnimationAction Animation="{Binding ElementName=ImageZoomOutAnimation}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Border>
|
||||
</ItemContainer>
|
||||
</DataTemplate>
|
||||
</cwucont:AdaptiveGridView.ItemTemplate>
|
||||
</cwucont:AdaptiveGridView>
|
||||
</ItemsView.ItemTemplate>
|
||||
</ItemsView>
|
||||
</DataTemplate>
|
||||
</shc:ScopedPage.Resources>
|
||||
<Grid>
|
||||
<ScrollViewer Padding="0,0,4,0">
|
||||
<ScrollViewer Padding="0,0,0,0">
|
||||
<StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="16,16,12,0"
|
||||
Margin="16,16,16,0"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="{Binding GreetingText}"/>
|
||||
<TextBlock Margin="16,0,16,0" Text="{Binding UserOptions.UserName}"/>
|
||||
<TextBlock Margin="16,0" Text="{Binding UserOptions.UserName}"/>
|
||||
|
||||
<ItemsControl
|
||||
Margin="16,16,12,0"
|
||||
@@ -190,26 +195,33 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<cwucont:AdaptiveGridView
|
||||
Margin="16,16,0,0"
|
||||
<ItemsView
|
||||
Margin="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
cwa:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="{StaticResource AdaptiveGridViewDesiredWidth}"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
IsItemInvokedEnabled="False"
|
||||
ItemsSource="{Binding Cards, Mode=OneWay}"
|
||||
SelectionMode="None"
|
||||
StretchContentForSingleRow="False">
|
||||
<shvca:LaunchGameCard Height="{StaticResource HomeAdaptiveCardHeight}"/>
|
||||
<shvca:GachaStatisticsCard/>
|
||||
<shvca:AchievementCard/>
|
||||
<shvca:DailyNoteCard/>
|
||||
|
||||
<!--<Border Style="{StaticResource BorderCardStyle}">
|
||||
<TextBlock Text="养成计划"/>
|
||||
</Border>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<TextBlock Text="深渊"/>
|
||||
</Border>-->
|
||||
</cwucont:AdaptiveGridView>
|
||||
Visibility="{Binding Cards.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
|
||||
<ItemsView.Layout>
|
||||
<UniformGridLayout
|
||||
ItemsJustification="Start"
|
||||
ItemsStretch="Fill"
|
||||
MinColumnSpacing="12"
|
||||
MinItemHeight="180"
|
||||
MinItemWidth="300"
|
||||
MinRowSpacing="12"/>
|
||||
</ItemsView.Layout>
|
||||
<ItemsView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ItemContainer>
|
||||
<ItemContainer.Resources>
|
||||
<SolidColorBrush x:Key="ItemContainerPointerOverBackground" Color="Transparent"/>
|
||||
</ItemContainer.Resources>
|
||||
<ContentControl HorizontalContentAlignment="Stretch" Content="{Binding Card}"/>
|
||||
</ItemContainer>
|
||||
</DataTemplate>
|
||||
</ItemsView.ItemTemplate>
|
||||
</ItemsView>
|
||||
</StackPanel>
|
||||
|
||||
<Pivot Style="{StaticResource DefaultPivotStyle}">
|
||||
|
||||
@@ -66,11 +66,7 @@
|
||||
Margin="6,6,6,6"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Projects}"
|
||||
SelectedItem="{Binding SelectedProject, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
SelectedItem="{Binding SelectedProject, Mode=TwoWay}"/>
|
||||
</AppBarElementContainer>
|
||||
<AppBarButton
|
||||
Command="{Binding AddProjectCommand}"
|
||||
|
||||
@@ -36,11 +36,7 @@
|
||||
Margin="16,6,0,6"
|
||||
DisplayMemberPath="Uid"
|
||||
ItemsSource="{Binding Archives}"
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/>
|
||||
</Pivot.LeftHeader>
|
||||
<Pivot.RightHeader>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
<Grid>
|
||||
<Image
|
||||
VerticalAlignment="Center"
|
||||
Source="ms-appx:///Assets/Square44x44Logo.targetsize-256.png"
|
||||
Stretch="UniformToFill"/>
|
||||
<Grid Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}">
|
||||
Source="ms-appx:///Resource/BlurBackground.png"
|
||||
Stretch="Fill"/>
|
||||
<Grid Background="{ThemeResource SystemControlBackgroundAltMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -91,6 +91,8 @@
|
||||
Description="{Binding HutaoOptions.WebView2Version}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"/>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingShellExperienceHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCreateDesktopShortcutAction}"
|
||||
Command="{Binding CreateDesktopShortcutCommand}"
|
||||
@@ -119,28 +121,68 @@
|
||||
SelectedItem="{Binding SelectedBackdropType, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewpageSettingHomeHeader}"/>
|
||||
<cwc:SettingsExpander
|
||||
Description="{shcm:ResourceString Name=ViewpageSettingHomeCardDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewpageSettingHomeCardHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<cwc:SettingsExpander.Items>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewpageSettingHomeCardItemLaunchGameHeader}">
|
||||
<ToggleSwitch
|
||||
IsOn="{Binding HomeCardOptions.IsHomeCardLaunchGamePresented, Mode=TwoWay}"
|
||||
OffContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOff}"
|
||||
OnContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOn}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewpageSettingHomeCardItemgachaStatisticsHeader}">
|
||||
<ToggleSwitch
|
||||
IsOn="{Binding HomeCardOptions.IsHomeCardGachaStatisticsPresented, Mode=TwoWay}"
|
||||
OffContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOff}"
|
||||
OnContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOn}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewpageSettingHomeCardItemAchievementHeader}">
|
||||
<ToggleSwitch
|
||||
IsOn="{Binding HomeCardOptions.IsHomeCardAchievementPresented, Mode=TwoWay}"
|
||||
OffContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOff}"
|
||||
OnContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOn}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewpageSettingHomeCardItemDailyNoteHeader}">
|
||||
<ToggleSwitch
|
||||
IsOn="{Binding HomeCardOptions.IsHomeCardDailyNotePresented, Mode=TwoWay}"
|
||||
OffContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOff}"
|
||||
OnContent="{shcm:ResourceString Name=ViewPageSettingHomeCardOn}"/>
|
||||
</cwc:SettingsCard>
|
||||
</cwc:SettingsExpander.Items>
|
||||
</cwc:SettingsExpander>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingGameHeader}"/>
|
||||
<InfoBar
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
Message="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"
|
||||
Severity="Informational"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingSetGamePathAction}"
|
||||
Command="{Binding SetGamePathCommand}"
|
||||
Description="{Binding Options.GamePath}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetGamePathHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
IsClickEnabled="True">
|
||||
<cwc:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock Foreground="{ThemeResource SystemErrorTextColor}" Text="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"/>
|
||||
<TextBlock Text="{Binding Options.GamePath}"/>
|
||||
</StackPanel>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingSetGamePathAction}"
|
||||
Command="{Binding SetPowerShellPathCommand}"
|
||||
Description="{Binding Options.PowerShellPath}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetPowerShellPathHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
IsClickEnabled="True">
|
||||
<cwc:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{shcm:ResourceString Name=ViewPageSettingSetPowerShellDescription}"/>
|
||||
<TextBlock Text="{Binding Options.PowerShellPath}"/>
|
||||
</StackPanel>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingDeleteCacheAction}"
|
||||
|
||||
@@ -315,6 +315,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
|
||||
if (result.Interrupted)
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
infoBarService.Warning(SH.ViewModelCultivationBatchAddIncompletedFormat.Format(result.SucceedCount, result.SkippedCount));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Hutao;
|
||||
using Snap.Hutao.View.Card;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -25,6 +27,7 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
|
||||
private AnnouncementWrapper? announcement;
|
||||
private string greetingText = SH.ViewPageHomeGreetingTextDefault;
|
||||
private ObservableCollection<Web.Hutao.HutaoAsAService.Announcement>? hutaoAnnouncements;
|
||||
private List<CardReference>? cards;
|
||||
|
||||
/// <summary>
|
||||
/// 公告
|
||||
@@ -43,8 +46,11 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
public string GreetingText { get => greetingText; set => SetProperty(ref greetingText, value); }
|
||||
|
||||
public List<CardReference>? Cards { get => cards; set => SetProperty(ref cards, value); }
|
||||
|
||||
protected override ValueTask<bool> InitializeUIAsync()
|
||||
{
|
||||
InitializeDashboard();
|
||||
InitializeInGameAnnouncementAsync().SafeForget();
|
||||
InitializeHutaoAnnouncementAsync().SafeForget();
|
||||
UpdateGreetingText();
|
||||
@@ -105,4 +111,31 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeDashboard()
|
||||
{
|
||||
List<CardReference> 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;
|
||||
}
|
||||
}
|
||||
33
src/Snap.Hutao/Snap.Hutao/ViewModel/HomeCardOptions.cs
Normal file
33
src/Snap.Hutao/Snap.Hutao/ViewModel/HomeCardOptions.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public HutaoUserOptions UserOptions { get => hutaoUserOptions; }
|
||||
|
||||
public HomeCardOptions HomeCardOptions { get => homeCardOptions; }
|
||||
|
||||
/// <summary>
|
||||
/// 选中的背景类型
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user