1
0
mirror of https://github.com/wangdage12/Snap.Hutao.git synced 2026-07-31 04:10:25 +08:00

在 我的角色 同步角色 批量添加或更新到当前养成计划时,增加 清空已经角色和武器信息 勾选框。如勾选该项目,在更新计划前会清空 培养计划中,角色和武器的信息。另外,当点 确认,更新完数据后,刷新现 养成计划。

This commit is contained in:
mfkvfhpdx
2026-05-04 11:16:01 +08:00
parent c6a2212caa
commit ed4626a74c
10 changed files with 105 additions and 4 deletions
@@ -1349,6 +1349,9 @@ Space Available: {2}</value>
<data name="ViewDialogCultivateBatchWeaponLevelTarget" xml:space="preserve">
<value>Weapon Target Level</value>
</data>
<data name="ViewDialogCultivateBatchClearAvatarAndWeaponEntries" xml:space="preserve">
<value>Clear existing character and weapon entries before updating</value>
</data>
<data name="ViewDialogCultivateProjectInputPlaceholder" xml:space="preserve">
<value>Enter the plan name here</value>
</data>
@@ -1391,6 +1391,9 @@
<data name="ViewDialogCultivateBatchWeaponLevelTarget" xml:space="preserve">
<value>武器目标等级</value>
</data>
<data name="ViewDialogCultivateBatchClearAvatarAndWeaponEntries" xml:space="preserve">
<value>更新计划前先清空已有角色与武器条目</value>
</data>
<data name="ViewDialogCultivateProjectInputPlaceholder" xml:space="preserve">
<value>在此处输入计划名称</value>
</data>
@@ -178,6 +178,48 @@ internal sealed partial class CultivationService : ICultivationService
cultivationRepository.RemoveCultivateEntryById(entryId);
}
public async ValueTask RemoveAvatarAndWeaponEntriesForCurrentProjectAsync()
{
IAdvancedDbCollectionView<CultivateProject> projects = await GetProjectCollectionAsync().ConfigureAwait(false);
if (!await EnsureCurrentProjectAsync(projects).ConfigureAwait(false))
{
return;
}
ArgumentNullException.ThrowIfNull(projects.CurrentItem);
Guid projectId = projects.CurrentItem.InnerId;
await taskContext.SwitchToBackgroundAsync();
ImmutableArray<CultivateEntry> entries = cultivationRepository.GetCultivateEntryImmutableArrayByProjectId(projectId);
List<Guid> weaponEntryIds = new(entries.Length);
List<Guid> avatarEntryIds = new(entries.Length);
foreach (ref readonly CultivateEntry entry in entries.AsSpan())
{
switch (entry.Type)
{
case CultivateType.Weapon:
weaponEntryIds.Add(entry.InnerId);
break;
case CultivateType.AvatarAndSkill:
avatarEntryIds.Add(entry.InnerId);
break;
}
}
foreach (Guid id in weaponEntryIds)
{
cultivationRepository.RemoveCultivateEntryById(id);
}
foreach (Guid id in avatarEntryIds)
{
cultivationRepository.RemoveCultivateEntryById(id);
}
entryCollectionCache.TryRemove(projectId, out _);
}
public void SaveCultivateItem(CultivateItemView item)
{
cultivationRepository.UpdateCultivateItem(item.Entity);
@@ -23,6 +23,11 @@ internal interface ICultivationService
ValueTask RemoveCultivateEntryAsync(Guid entryId);
/// <summary>
/// 移除当前选中养成计划中角色与武器类型的全部养成条目。
/// </summary>
ValueTask RemoveAvatarAndWeaponEntriesForCurrentProjectAsync();
ValueTask RemoveProjectAsync(CultivateProject project);
ValueTask<ConsumptionSaveResult> SaveConsumptionAsync(InputConsumption inputConsumption);
@@ -77,5 +77,10 @@
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyOverwriteExisting}"/>
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyCreateNewEntry}"/>
</RadioButtons>
<CheckBox
Margin="0,13,0,0"
Content="{shuxm:ResourceString Name=ViewDialogCultivateBatchClearAvatarAndWeaponEntries}"
IsChecked="{x:Bind ClearAvatarAndWeaponEntriesBeforeSync, Mode=TwoWay}"/>
</StackPanel>
</ContentDialog>
@@ -10,6 +10,7 @@ using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
namespace Snap.Hutao.UI.Xaml.View.Dialog;
[DependencyProperty<AvatarPromotionDelta>("PromotionDelta", NotNull = true, CreateDefaultValueCallbackName = nameof(CreatePromotionDeltaDefaultValue))]
[DependencyProperty<bool>("ClearAvatarAndWeaponEntriesBeforeSync", DefaultValue = false, NotNull = true)]
internal sealed partial class CultivatePromotionDeltaBatchDialog : ContentDialog
{
private readonly IContentDialogFactory contentDialogFactory;
@@ -45,7 +46,7 @@ internal sealed partial class CultivatePromotionDeltaBatchDialog : ContentDialog
LocalSetting.Set(SettingKeys.CultivationWeapon90LevelTarget, weapon.LevelTarget);
}
return new(true, new(PromotionDelta, (ConsumptionSaveStrategyKind)SaveModeSelector.SelectedIndex));
return new(true, new CultivatePromotionDeltaOptions(PromotionDelta, (ConsumptionSaveStrategyKind)SaveModeSelector.SelectedIndex, ClearAvatarAndWeaponEntriesBeforeSync));
}
private static object CreatePromotionDeltaDefaultValue()
@@ -8,7 +8,7 @@ namespace Snap.Hutao.UI.Xaml.View.Dialog;
internal sealed class CultivatePromotionDeltaOptions
{
public CultivatePromotionDeltaOptions(AvatarPromotionDelta delta, ConsumptionSaveStrategyKind strategy)
public CultivatePromotionDeltaOptions(AvatarPromotionDelta delta, ConsumptionSaveStrategyKind strategy, bool clearAvatarAndWeaponEntriesBeforeSync = false)
{
delta.AvatarLevelTarget = delta.AvatarLevelTarget switch
{
@@ -19,9 +19,15 @@ internal sealed class CultivatePromotionDeltaOptions
Delta = delta;
Strategy = strategy;
ClearAvatarAndWeaponEntriesBeforeSync = clearAvatarAndWeaponEntriesBeforeSync;
}
public AvatarPromotionDelta Delta { get; }
public ConsumptionSaveStrategyKind Strategy { get; }
/// <summary>
/// 批量同步前是否清空当前计划中已有的角色与武器养成条目(不含家具等其它类型)。
/// </summary>
public bool ClearAvatarAndWeaponEntriesBeforeSync { get; }
}
@@ -21,6 +21,7 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.UI.Xaml.Control.AutoSuggestBox;
using Snap.Hutao.UI.Xaml.View.Dialog;
using Snap.Hutao.ViewModel.Cultivation;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
using System.Collections.Immutable;
@@ -286,6 +287,11 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
BatchCultivateResult result = default;
using (await scopeContext.ContentDialogFactory.BlockAsync(progressDialog).ConfigureAwait(false))
{
if (baseline.ClearAvatarAndWeaponEntriesBeforeSync)
{
await scopeContext.CultivationService.RemoveAvatarAndWeaponEntriesForCurrentProjectAsync().ConfigureAwait(false);
}
ImmutableArray<CalculatorAvatarPromotionDelta>.Builder deltasBuilder = ImmutableArray.CreateBuilder<CalculatorAvatarPromotionDelta>();
foreach (AvatarView avatar in targetAvatars)
{
@@ -305,7 +311,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
foreach ((CalculatorConsumption consumption, CalculatorAvatarPromotionDelta delta) in batchConsumption.Items.Zip(deltas))
{
if (!await SaveCultivationAsync(consumption, new(delta, baseline.Strategy), true).ConfigureAwait(false))
if (!await SaveCultivationAsync(consumption, new CultivatePromotionDeltaOptions(delta, baseline.Strategy), true).ConfigureAwait(false))
{
break;
}
@@ -314,6 +320,8 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
}
}
scopeContext.Messenger.Send(CultivationProjectEntriesChangedMessage.Empty);
InfoBarMessage message = result.SkippedCount > 0
? InfoBarMessage.Warning(SH.FormatViewModelCultivationBatchAddIncompleted(result.SucceedCount, result.SkippedCount))
: InfoBarMessage.Success(SH.FormatViewModelCultivationBatchAddCompleted(result.SucceedCount, result.SkippedCount));
@@ -0,0 +1,16 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.ViewModel.Cultivation;
/// <summary>
/// 当前养成计划的条目在 UI 外被批量变更(例如从「我的角色」同步)后,通知养成页刷新列表与统计。
/// </summary>
internal sealed class CultivationProjectEntriesChangedMessage
{
public static readonly CultivationProjectEntriesChangedMessage Empty = new();
private CultivationProjectEntriesChangedMessage()
{
}
}
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
@@ -29,7 +30,7 @@ namespace Snap.Hutao.ViewModel.Cultivation;
[SuppressMessage("", "CA1001")]
[BindableCustomPropertyProvider]
[Service(ServiceLifetime.Scoped)]
internal sealed partial class CultivationViewModel : Abstraction.ViewModel
internal sealed partial class CultivationViewModel : Abstraction.ViewModel, IRecipient<CultivationProjectEntriesChangedMessage>
{
private readonly ExclusiveTokenProvider exclusiveTokenProvider = new();
@@ -132,6 +133,17 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
UpdateEntryCollectionAsync(Projects?.CurrentItem).SafeForget();
}
public async void Receive(CultivationProjectEntriesChangedMessage message)
{
await taskContext.SwitchToMainThreadAsync();
if (Projects?.CurrentItem is null)
{
return;
}
await UpdateEntryCollectionAsync(Projects.CurrentItem).ConfigureAwait(false);
}
[Command("AddProjectCommand")]
private async Task AddProjectAsync()
{