mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
cultivation save mode
This commit is contained in:
@@ -1247,6 +1247,18 @@
|
||||
<data name="ViewDialogCultivatePromotionDeltaTitle" xml:space="preserve">
|
||||
<value>添加或更新到当前养成计划</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivationConsumptionSaveStrategyCreateNewEntry" xml:space="preserve">
|
||||
<value>总是创建新的养成目标物品</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivationConsumptionSaveStrategyHeader" xml:space="preserve">
|
||||
<value>保存方式</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivationConsumptionSaveStrategyOverwriteExisting" xml:space="preserve">
|
||||
<value>覆盖存在的养成目标物品</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivationConsumptionSaveStrategyPreserveExisting" xml:space="preserve">
|
||||
<value>保留存在的养成目标物品</value>
|
||||
</data>
|
||||
<data name="ViewDialogDailyNoteNotificationDailyTaskNotify" xml:space="preserve">
|
||||
<value>每日委托上线提醒</value>
|
||||
</data>
|
||||
@@ -1598,6 +1610,15 @@
|
||||
<data name="ViewModelCultivationBatchAddIncompletedFormat" xml:space="preserve">
|
||||
<value>操作未全部完成:添加 / 更新:{0} 个,跳过 {1} 个</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationConsumptionSaveNoItemHint" xml:space="preserve">
|
||||
<value>选定的等级不需要养成材料</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationConsumptionSaveNoProjectHint" xml:space="preserve">
|
||||
<value>尚未创建并选择养成计划</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationConsumptionSaveSkippedHint" xml:space="preserve">
|
||||
<value>已存在该物品的养成项目</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationEntryAddSuccess" xml:space="preserve">
|
||||
<value>已成功添加至当前养成计划</value>
|
||||
</data>
|
||||
|
||||
@@ -8,12 +8,10 @@ using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.ViewModel.Achievement;
|
||||
using System.Collections.ObjectModel;
|
||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||
|
||||
namespace Snap.Hutao.Service.Achievement;
|
||||
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped, typeof(IAchievementService))]
|
||||
internal sealed partial class AchievementService : IAchievementService
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.UI.Xaml.Data;
|
||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||
|
||||
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||
@@ -38,7 +39,7 @@ internal sealed partial class SummaryFactory : ISummaryFactory
|
||||
|
||||
return new()
|
||||
{
|
||||
Avatars = new(views),
|
||||
Avatars = views.ToAdvancedCollectionView(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
internal enum ConsumptionSaveResultKind
|
||||
{
|
||||
NoItem,
|
||||
NoProject,
|
||||
Skipped,
|
||||
Added,
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
internal enum ConsumptionSaveStrategyKind
|
||||
{
|
||||
PreserveExisting,
|
||||
OverwriteExisting,
|
||||
CreateNewEntry,
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using Snap.Hutao.Service.Inventory;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.Cultivation;
|
||||
using System.Collections.ObjectModel;
|
||||
using CalculateItem = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Item;
|
||||
using ModelItem = Snap.Hutao.Model.Item;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
@@ -115,45 +114,54 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<CalculateItem> items, LevelInformation levelInformation)
|
||||
public async ValueTask<ConsumptionSaveResultKind> SaveConsumptionAsync(InputConsumption inputConsumption)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
if (inputConsumption.Items.Count == 0)
|
||||
{
|
||||
return true;
|
||||
return ConsumptionSaveResultKind.NoItem;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
if (Projects.CurrentItem is null)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Projects.MoveCurrentTo(Projects.SourceCollection.SelectedOrDefault());
|
||||
if (Projects.CurrentItem is null)
|
||||
{
|
||||
return false;
|
||||
return ConsumptionSaveResultKind.NoProject;
|
||||
}
|
||||
}
|
||||
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
CultivateEntry? entry = type is CultivateType.AvatarAndSkill
|
||||
? cultivationDbService.GetCultivateEntryByProjectIdAndItemId(Projects.CurrentItem.InnerId, itemId)
|
||||
: default;
|
||||
|
||||
CultivateEntry? entry = default;
|
||||
|
||||
if (inputConsumption.Strategy is ConsumptionSaveStrategyKind.PreserveExisting or ConsumptionSaveStrategyKind.OverwriteExisting)
|
||||
{
|
||||
entry = cultivationDbService.GetCultivateEntryByProjectIdAndItemId(Projects.CurrentItem.InnerId, inputConsumption.ItemId);
|
||||
|
||||
if (inputConsumption.Strategy is ConsumptionSaveStrategyKind.PreserveExisting && entry is not null)
|
||||
{
|
||||
return ConsumptionSaveResultKind.Skipped;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry is null)
|
||||
{
|
||||
entry = CultivateEntry.From(Projects.CurrentItem.InnerId, type, itemId);
|
||||
entry = CultivateEntry.From(Projects.CurrentItem.InnerId, inputConsumption.Type, inputConsumption.ItemId);
|
||||
cultivationDbService.AddCultivateEntry(entry);
|
||||
}
|
||||
|
||||
Guid entryId = entry.InnerId;
|
||||
|
||||
cultivationDbService.RemoveLevelInformationByEntryId(entryId);
|
||||
CultivateEntryLevelInformation entryLevelInformation = CultivateEntryLevelInformation.From(entryId, type, levelInformation);
|
||||
CultivateEntryLevelInformation entryLevelInformation = CultivateEntryLevelInformation.From(entryId, inputConsumption.Type, inputConsumption.LevelInformation);
|
||||
cultivationDbService.AddLevelInformation(entryLevelInformation);
|
||||
|
||||
cultivationDbService.RemoveCultivateItemRangeByEntryId(entryId);
|
||||
IEnumerable<CultivateItem> toAdd = items.Select(item => CultivateItem.From(entryId, item));
|
||||
IEnumerable<CultivateItem> toAdd = inputConsumption.Items.Select(item => CultivateItem.From(entryId, item));
|
||||
cultivationDbService.AddCultivateItemRange(toAdd);
|
||||
|
||||
return true;
|
||||
return ConsumptionSaveResultKind.Added;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -3,22 +3,13 @@
|
||||
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Primitive;
|
||||
using Snap.Hutao.ViewModel.Cultivation;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成计算服务
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal interface ICultivationService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取用于绑定的项目集合
|
||||
/// </summary>
|
||||
AdvancedDbCollectionView<CultivateProject> Projects { get; }
|
||||
|
||||
ValueTask<ObservableCollection<CultivateEntryView>> GetCultivateEntriesAsync(CultivateProject cultivateProject, ICultivationMetadataContext context);
|
||||
@@ -26,32 +17,13 @@ internal interface ICultivationService
|
||||
ValueTask<ObservableCollection<StatisticsCultivateItem>> GetStatisticsCultivateItemCollectionAsync(
|
||||
CultivateProject cultivateProject, ICultivationMetadataContext context, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 删除养成清单
|
||||
/// </summary>
|
||||
/// <param name="entryId">入口Id</param>
|
||||
/// <returns>任务</returns>
|
||||
ValueTask RemoveCultivateEntryAsync(Guid entryId);
|
||||
|
||||
/// <summary>
|
||||
/// 异步移除项目
|
||||
/// </summary>
|
||||
/// <param name="project">项目</param>
|
||||
/// <returns>任务</returns>
|
||||
ValueTask RemoveProjectAsync(CultivateProject project);
|
||||
|
||||
ValueTask<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<Item> items, LevelInformation levelInformation);
|
||||
ValueTask<ConsumptionSaveResultKind> SaveConsumptionAsync(InputConsumption inputConsumption);
|
||||
|
||||
/// <summary>
|
||||
/// 保存养成物品状态
|
||||
/// </summary>
|
||||
/// <param name="item">养成物品</param>
|
||||
void SaveCultivateItem(CultivateItemView item);
|
||||
|
||||
/// <summary>
|
||||
/// 异步尝试添加新的项目
|
||||
/// </summary>
|
||||
/// <param name="project">项目</param>
|
||||
/// <returns>添加操作的结果</returns>
|
||||
ValueTask<ProjectAddResultKind> TryAddProjectAsync(CultivateProject project);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Entity.Primitive;
|
||||
using CalculateItem = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Item;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
internal sealed class InputConsumption
|
||||
{
|
||||
public required CultivateType Type { get; init; }
|
||||
|
||||
public required uint ItemId { get; init; }
|
||||
|
||||
public required List<CalculateItem> Items { get; init; }
|
||||
|
||||
public required LevelInformation LevelInformation { get; init; }
|
||||
|
||||
public required ConsumptionSaveStrategyKind Strategy { get; init; }
|
||||
}
|
||||
@@ -203,7 +203,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
AsyncBarrier barrier = new(4);
|
||||
|
||||
List<HistoryWish> historyWishes = historyWishBuilders
|
||||
.Where(b => appOptions.IsEmptyHistoryWishVisible || (!b.IsEmpty))
|
||||
.Where(b => appOptions.IsEmptyHistoryWishVisible || !b.IsEmpty)
|
||||
.OrderByDescending(builder => builder.From)
|
||||
.ThenBy(builder => builder.ConfigType, GachaTypeComparer.Shared)
|
||||
.Select(builder => builder.ToHistoryWish())
|
||||
@@ -212,7 +212,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
return new()
|
||||
{
|
||||
// history
|
||||
HistoryWishes = new(historyWishes),
|
||||
HistoryWishes = historyWishes.ToAdvancedCollectionView(),
|
||||
|
||||
// avatars
|
||||
OrangeAvatars = orangeAvatarCounter.ToStatisticsList(),
|
||||
|
||||
@@ -21,9 +21,15 @@ internal sealed partial class GameAccountService : IGameAccountService
|
||||
|
||||
private ObservableReorderableDbCollection<GameAccount>? gameAccounts;
|
||||
|
||||
public ObservableReorderableDbCollection<GameAccount> GameAccountCollection
|
||||
public async ValueTask<ObservableReorderableDbCollection<GameAccount>> GetGameAccountCollectionAsync()
|
||||
{
|
||||
get => gameAccounts ??= gameDbService.GetGameAccountCollection();
|
||||
if (gameAccounts is null)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
gameAccounts = gameDbService.GetGameAccountCollection();
|
||||
}
|
||||
|
||||
return gameAccounts;
|
||||
}
|
||||
|
||||
public async ValueTask<GameAccount?> DetectGameAccountAsync(SchemeType schemeType)
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace Snap.Hutao.Service.Game.Account;
|
||||
|
||||
internal interface IGameAccountService
|
||||
{
|
||||
ObservableReorderableDbCollection<GameAccount> GameAccountCollection { get; }
|
||||
|
||||
ValueTask AttachGameAccountToUidAsync(GameAccount gameAccount, string uid);
|
||||
|
||||
GameAccount? DetectCurrentGameAccount(SchemeType schemeType);
|
||||
|
||||
ValueTask<GameAccount?> DetectGameAccountAsync(SchemeType schemeType);
|
||||
|
||||
ValueTask<ObservableReorderableDbCollection<GameAccount>> GetGameAccountCollectionAsync();
|
||||
|
||||
ValueTask ModifyGameAccountAsync(GameAccount gameAccount);
|
||||
|
||||
ValueTask RemoveGameAccountAsync(GameAccount gameAccount);
|
||||
|
||||
@@ -11,10 +11,6 @@ using Snap.Hutao.Service.Game.PathAbstraction;
|
||||
|
||||
namespace Snap.Hutao.Service.Game;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏服务
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(IGameServiceFacade))]
|
||||
internal sealed partial class GameServiceFacade : IGameServiceFacade
|
||||
@@ -23,55 +19,46 @@ internal sealed partial class GameServiceFacade : IGameServiceFacade
|
||||
private readonly IGameAccountService gameAccountService;
|
||||
private readonly IGamePathService gamePathService;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableReorderableDbCollection<GameAccount> GameAccountCollection
|
||||
public ValueTask<ObservableReorderableDbCollection<GameAccount>> GetGameAccountCollectionAsync()
|
||||
{
|
||||
get => gameAccountService.GameAccountCollection;
|
||||
return gameAccountService.GetGameAccountCollectionAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<ValueResult<bool, string>> GetGamePathAsync()
|
||||
{
|
||||
return gamePathService.SilentGetGamePathAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ChannelOptions GetChannelOptions()
|
||||
{
|
||||
return gameChannelOptionsService.GetChannelOptions();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<GameAccount?> DetectGameAccountAsync(SchemeType scheme)
|
||||
{
|
||||
return gameAccountService.DetectGameAccountAsync(scheme);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameAccount? DetectCurrentGameAccount(SchemeType scheme)
|
||||
{
|
||||
return gameAccountService.DetectCurrentGameAccount(scheme);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask AttachGameAccountToUidAsync(GameAccount gameAccount, string uid)
|
||||
{
|
||||
return gameAccountService.AttachGameAccountToUidAsync(gameAccount, uid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask ModifyGameAccountAsync(GameAccount gameAccount)
|
||||
{
|
||||
return gameAccountService.ModifyGameAccountAsync(gameAccount);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask RemoveGameAccountAsync(GameAccount gameAccount)
|
||||
{
|
||||
return gameAccountService.RemoveGameAccountAsync(gameAccount);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsGameRunning()
|
||||
{
|
||||
return LaunchExecutionEnsureGameNotRunningHandler.IsGameRunning(out _);
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace Snap.Hutao.Service.Game;
|
||||
|
||||
internal interface IGameServiceFacade
|
||||
{
|
||||
ObservableReorderableDbCollection<GameAccount> GameAccountCollection { get; }
|
||||
|
||||
ValueTask AttachGameAccountToUidAsync(GameAccount gameAccount, string uid);
|
||||
|
||||
ValueTask<GameAccount?> DetectGameAccountAsync(SchemeType scheme);
|
||||
@@ -27,4 +25,6 @@ internal interface IGameServiceFacade
|
||||
ValueTask RemoveGameAccountAsync(GameAccount gameAccount);
|
||||
|
||||
GameAccount? DetectCurrentGameAccount(SchemeType scheme);
|
||||
|
||||
ValueTask<ObservableReorderableDbCollection<GameAccount>> GetGameAccountCollectionAsync();
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Abstraction;
|
||||
using Snap.Hutao.Model.Entity.Extension;
|
||||
using Snap.Hutao.UI.Xaml.Data;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
using Snap.Hutao.Web.Hoyolab.Passport;
|
||||
@@ -213,7 +214,7 @@ internal sealed partial class UserInitializationService : IUserInitializationSer
|
||||
|
||||
if (userGameRolesResponse.IsOk())
|
||||
{
|
||||
user.UserGameRoles = new(userGameRolesResponse.Data.List);
|
||||
user.UserGameRoles = userGameRolesResponse.Data.List.ToAdvancedCollectionView();
|
||||
return user.UserGameRoles.Count > 0;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -100,7 +100,11 @@ internal sealed class UniformStaggeredLayoutState
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
RecycleElements();
|
||||
if (items.Count > 0)
|
||||
{
|
||||
RecycleElements();
|
||||
}
|
||||
|
||||
ClearColumns();
|
||||
ClearItems();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using CommunityToolkit.WinUI.Collections;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
</cwc:HeaderedContentControl>
|
||||
</cwc:UniformGrid>
|
||||
<RadioButtons
|
||||
Name="ImportModeSelector"
|
||||
x:Name="ImportModeSelector"
|
||||
Grid.Row="1"
|
||||
Margin="0,16,0,0"
|
||||
Header="{shuxm:ResourceString Name=ViewDialogAchievementArchiveImportStrategy}"
|
||||
|
||||
@@ -8,20 +8,11 @@ using Snap.Hutao.Service.Achievement;
|
||||
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// 成就对话框
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[DependencyProperty("UIAF", typeof(UIAF))]
|
||||
internal sealed partial class AchievementImportDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的成就对话框
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="uiaf">uiaf数据</param>
|
||||
public AchievementImportDialog(IServiceProvider serviceProvider, UIAF uiaf)
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -30,10 +21,6 @@ internal sealed partial class AchievementImportDialog : ContentDialog
|
||||
UIAF = uiaf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取导入选项
|
||||
/// </summary>
|
||||
/// <returns>导入选项</returns>
|
||||
public async ValueTask<ValueResult<bool, ImportStrategyKind>> GetImportStrategyAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
@@ -73,5 +73,14 @@
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.Weapon.LevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
|
||||
<RadioButtons
|
||||
x:Name="SaveModeSelector"
|
||||
Header="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyHeader}"
|
||||
SelectedIndex="0">
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyPreserveExisting}"/>
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyOverwriteExisting}"/>
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyCreateNewEntry}"/>
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
@@ -21,7 +22,7 @@ internal sealed partial class CultivatePromotionDeltaBatchDialog : ContentDialog
|
||||
PromotionDelta = AvatarPromotionDelta.CreateForBaseline();
|
||||
}
|
||||
|
||||
public async ValueTask<ValueResult<bool, AvatarPromotionDelta>> GetPromotionDeltaBaselineAsync()
|
||||
public async ValueTask<ValueResult<bool, CultivatePromotionDeltaOptions>> GetPromotionDeltaBaselineAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
@@ -50,6 +51,6 @@ internal sealed partial class CultivatePromotionDeltaBatchDialog : ContentDialog
|
||||
LocalSetting.Set(SettingKeys.CultivationWeapon90LevelTarget, weapon.LevelTarget);
|
||||
}
|
||||
|
||||
return new(true, PromotionDelta);
|
||||
return new(true, new(PromotionDelta, (ConsumptionSaveStrategyKind)SaveModeSelector.SelectedIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,16 +64,14 @@
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ContentDialog.Resources>
|
||||
<Grid>
|
||||
<Grid Margin="0,8,0,0" RowSpacing="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{x:Bind Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<StackPanel Grid.Row="0" Visibility="{x:Bind Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Grid
|
||||
Padding="8"
|
||||
DataContext="{x:Bind Avatar}"
|
||||
@@ -123,10 +121,7 @@
|
||||
<ItemsControl ItemTemplate="{StaticResource SkillTemplate}" ItemsSource="{x:Bind Avatar.Skills}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,6,0,0"
|
||||
Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<StackPanel Grid.Row="1" Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Grid
|
||||
Padding="8"
|
||||
DataContext="{x:Bind Weapon}"
|
||||
@@ -174,5 +169,14 @@
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<RadioButtons
|
||||
x:Name="SaveModeSelector"
|
||||
Grid.Row="2"
|
||||
Header="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyHeader}"
|
||||
SelectedIndex="0">
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyPreserveExisting}"/>
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyOverwriteExisting}"/>
|
||||
<RadioButton Content="{shuxm:ResourceString Name=ViewDialogCultivationConsumptionSaveStrategyCreateNewEntry}"/>
|
||||
</RadioButtons>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
</ContentDialog>
|
||||
@@ -4,25 +4,17 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Model.Calculable;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// 养成计算对话框
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[DependencyProperty("Avatar", typeof(ICalculableAvatar))]
|
||||
[DependencyProperty("Weapon", typeof(ICalculableWeapon))]
|
||||
internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的养成计算对话框
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="options">选项</param>
|
||||
public CultivatePromotionDeltaDialog(IServiceProvider serviceProvider, CalculableOptions options)
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -33,11 +25,7 @@ internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
Weapon = options.Weapon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取提升差异
|
||||
/// </summary>
|
||||
/// <returns>提升差异</returns>
|
||||
public async ValueTask<ValueResult<bool, AvatarPromotionDelta>> GetPromotionDeltaAsync()
|
||||
public async ValueTask<ValueResult<bool, CultivatePromotionDeltaOptions>> GetPromotionDeltaAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
@@ -66,6 +54,6 @@ internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
},
|
||||
};
|
||||
|
||||
return new(true, delta);
|
||||
return new(true, new(delta, (ConsumptionSaveStrategyKind)SaveModeSelector.SelectedIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
|
||||
internal sealed class CultivatePromotionDeltaOptions
|
||||
{
|
||||
public CultivatePromotionDeltaOptions(AvatarPromotionDelta delta, ConsumptionSaveStrategyKind strategy)
|
||||
{
|
||||
Delta = delta;
|
||||
Strategy = strategy;
|
||||
}
|
||||
|
||||
public AvatarPromotionDelta Delta { get; set; }
|
||||
|
||||
public ConsumptionSaveStrategyKind Strategy { get; set; }
|
||||
}
|
||||
@@ -107,13 +107,15 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> ReceiveAsync(INavigationData data)
|
||||
{
|
||||
if (await Initialization.Task.ConfigureAwait(false))
|
||||
if (!await Initialization.Task.ConfigureAwait(false))
|
||||
{
|
||||
if (data.Data is AppActivation.ImportUIAFFromClipboard)
|
||||
{
|
||||
await ImportUIAFFromClipboardAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.Data is AppActivation.ImportUIAFFromClipboard)
|
||||
{
|
||||
await ImportUIAFFromClipboardAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -206,7 +208,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
[Command("RemoveArchiveCommand")]
|
||||
private async Task RemoveArchiveAsync()
|
||||
{
|
||||
if (Archives is null || !(Archives.CurrentItem is { } current))
|
||||
if (Archives?.CurrentItem is not { } current)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +285,9 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
|
||||
private async ValueTask UpdateAchievementsAsync(EntityArchive? archive)
|
||||
{
|
||||
// TODO: immediately clear values
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
Achievements = default;
|
||||
|
||||
if (archive is null)
|
||||
{
|
||||
return;
|
||||
@@ -293,31 +297,29 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
.GetContextAsync<AchievementServiceMetadataContext>(CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!TryGetAchievements(archive, context, out List<AchievementView>? combined))
|
||||
if (!TryGetAchievements(archive, context, out AdvancedCollectionView<AchievementView>? combined))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AdvancedCollectionView<AchievementView> achievements = new(combined);
|
||||
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
Achievements = achievements;
|
||||
Achievements = combined;
|
||||
AchievementFinishPercent.Update(this);
|
||||
UpdateAchievementsFilterByGoal(AchievementGoals?.CurrentItem);
|
||||
UpdateAchievementsSort();
|
||||
}
|
||||
|
||||
private bool TryGetAchievements(EntityArchive archive, AchievementServiceMetadataContext context, [NotNullWhen(true)] out List<AchievementView>? combined)
|
||||
private bool TryGetAchievements(EntityArchive archive, AchievementServiceMetadataContext context, [NotNullWhen(true)] out AdvancedCollectionView<AchievementView>? view)
|
||||
{
|
||||
try
|
||||
{
|
||||
combined = scopeContext.AchievementService.GetAchievementViewList(archive, context);
|
||||
view = scopeContext.AchievementService.GetAchievementViewList(archive, context).ToAdvancedCollectionView();
|
||||
return true;
|
||||
}
|
||||
catch (HutaoException ex)
|
||||
{
|
||||
scopeContext.InfoBarService.Error(ex);
|
||||
combined = default;
|
||||
view = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -330,33 +332,41 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
return;
|
||||
}
|
||||
|
||||
Achievements.SortDescriptions.Clear();
|
||||
AchievementGoals.SortDescriptions.Clear();
|
||||
|
||||
if (IsUncompletedItemsFirst)
|
||||
using (Achievements.DeferRefresh())
|
||||
{
|
||||
Achievements.SortDescriptions.Add(achievementUncompletedItemsFirstSortDescription);
|
||||
Achievements.SortDescriptions.Add(achievementCompletionTimeSortDescription);
|
||||
AchievementGoals.SortDescriptions.Add(achievementGoalUncompletedItemsFirstSortDescription);
|
||||
}
|
||||
using (AchievementGoals.DeferRefresh())
|
||||
{
|
||||
Achievements.SortDescriptions.Clear();
|
||||
AchievementGoals.SortDescriptions.Clear();
|
||||
|
||||
Achievements.SortDescriptions.Add(achievementDefaultSortDescription);
|
||||
AchievementGoals.SortDescriptions.Add(achievementGoalDefaultSortDescription);
|
||||
if (IsUncompletedItemsFirst)
|
||||
{
|
||||
Achievements.SortDescriptions.Add(achievementUncompletedItemsFirstSortDescription);
|
||||
Achievements.SortDescriptions.Add(achievementCompletionTimeSortDescription);
|
||||
AchievementGoals.SortDescriptions.Add(achievementGoalUncompletedItemsFirstSortDescription);
|
||||
}
|
||||
|
||||
Achievements.SortDescriptions.Add(achievementDefaultSortDescription);
|
||||
AchievementGoals.SortDescriptions.Add(achievementGoalDefaultSortDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAchievementsFilterByGoal(AchievementGoalView? goal)
|
||||
{
|
||||
if (Achievements is not null)
|
||||
if (Achievements is null)
|
||||
{
|
||||
if (goal is null)
|
||||
{
|
||||
Achievements.Filter = default!;
|
||||
}
|
||||
else
|
||||
{
|
||||
Model.Primitive.AchievementGoalId goalId = goal.Id;
|
||||
Achievements.Filter = (AchievementView view) => view.Inner.Goal == goalId;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (goal is null)
|
||||
{
|
||||
Achievements.Filter = default!;
|
||||
}
|
||||
else
|
||||
{
|
||||
Model.Primitive.AchievementGoalId goalId = goal.Id;
|
||||
Achievements.Filter = (AchievementView view) => view.Inner.Goal == goalId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,10 +408,12 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
[Command("SaveAchievementCommand")]
|
||||
private void SaveAchievement(AchievementView? achievement)
|
||||
{
|
||||
if (achievement is not null)
|
||||
if (achievement is null)
|
||||
{
|
||||
scopeContext.AchievementService.SaveAchievement(achievement);
|
||||
AchievementFinishPercent.Update(this);
|
||||
return;
|
||||
}
|
||||
|
||||
scopeContext.AchievementService.SaveAchievement(achievement);
|
||||
AchievementFinishPercent.Update(this);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.DataTransfer;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Model.Calculable;
|
||||
using Snap.Hutao.Model.Entity.Primitive;
|
||||
using Snap.Hutao.Service.AvatarInfo;
|
||||
@@ -20,9 +18,7 @@ using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using CalculatorAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
|
||||
using CalculatorBatchConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.BatchConsumption;
|
||||
using CalculatorClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
|
||||
using CalculatorConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Consumption;
|
||||
using CalculatorItem = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Item;
|
||||
using CalculatorItemHelper = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.ItemHelper;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||
@@ -31,14 +27,7 @@ namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, IRecipient<UserAndUidChangedMessage>
|
||||
{
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly ICultivationService cultivationService;
|
||||
private readonly IAvatarInfoService avatarInfoService;
|
||||
private readonly IClipboardProvider clipboardProvider;
|
||||
private readonly CalculatorClient calculatorClient;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IUserService userService;
|
||||
private readonly AvatarPropertyViewModelScopeContext scopeContext;
|
||||
|
||||
private Summary? summary;
|
||||
|
||||
@@ -61,7 +50,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
|
||||
protected override async ValueTask<bool> InitializeOverrideAsync()
|
||||
{
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
{
|
||||
await RefreshCoreAsync(userAndUid, RefreshOption.None, CancellationToken).ConfigureAwait(false);
|
||||
return true;
|
||||
@@ -73,7 +62,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
[Command("RefreshFromEnkaApiCommand")]
|
||||
private async Task RefreshByEnkaApiAsync()
|
||||
{
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
{
|
||||
await RefreshCoreAsync(userAndUid, RefreshOption.RequestFromEnkaAPI, CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -82,7 +71,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
[Command("RefreshFromHoyolabGameRecordCommand")]
|
||||
private async Task RefreshByHoyolabGameRecordAsync()
|
||||
{
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
{
|
||||
await RefreshCoreAsync(userAndUid, RefreshOption.RequestFromHoyolabGameRecord, CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -91,7 +80,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
[Command("RefreshFromHoyolabCalculateCommand")]
|
||||
private async Task RefreshByHoyolabCalculateAsync()
|
||||
{
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is { } userAndUid)
|
||||
{
|
||||
await RefreshCoreAsync(userAndUid, RefreshOption.RequestFromHoyolabCalculate, CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -101,18 +90,19 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
{
|
||||
try
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
IsInitialized = false;
|
||||
|
||||
ValueResult<RefreshResultKind, Summary?> summaryResult;
|
||||
using (await EnterCriticalSectionAsync().ConfigureAwait(false))
|
||||
{
|
||||
ContentDialog dialog = await contentDialogFactory
|
||||
ContentDialog dialog = await scopeContext.ContentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyFetch)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
using (await dialog.BlockAsync(scopeContext.TaskContext).ConfigureAwait(false))
|
||||
{
|
||||
summaryResult = await avatarInfoService
|
||||
summaryResult = await scopeContext.AvatarInfoService
|
||||
.GetSummaryAsync(userAndUid, option, token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
@@ -121,7 +111,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
(RefreshResultKind result, Summary? summary) = summaryResult;
|
||||
if (result is RefreshResultKind.Ok)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
Summary = summary;
|
||||
Summary?.Avatars.MoveCurrentToFirstOrDefault();
|
||||
}
|
||||
@@ -130,16 +120,16 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
switch (result)
|
||||
{
|
||||
case RefreshResultKind.APIUnavailable:
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyEnkaApiUnavailable);
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelAvatarPropertyEnkaApiUnavailable);
|
||||
break;
|
||||
|
||||
case RefreshResultKind.StatusCodeNotSucceed:
|
||||
ArgumentNullException.ThrowIfNull(summary);
|
||||
infoBarService.Warning(summary.Message);
|
||||
scopeContext.InfoBarService.Warning(summary.Message);
|
||||
break;
|
||||
|
||||
case RefreshResultKind.ShowcaseNotOpen:
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyShowcaseNotOpen);
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelAvatarPropertyShowcaseNotOpen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +139,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
}
|
||||
finally
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
IsInitialized = true;
|
||||
}
|
||||
}
|
||||
@@ -162,41 +152,47 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
return;
|
||||
}
|
||||
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid)
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
scopeContext.InfoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar.Weapon is null)
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyCalculateWeaponNull);
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelAvatarPropertyCalculateWeaponNull);
|
||||
return;
|
||||
}
|
||||
|
||||
CalculableOptions options = new(avatar.ToCalculable(), avatar.Weapon.ToCalculable());
|
||||
CultivatePromotionDeltaDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CalculatorAvatarPromotionDelta delta) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
CultivatePromotionDeltaDialog dialog = await scopeContext.ContentDialogFactory
|
||||
.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CultivatePromotionDeltaOptions deltaOptions) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Response<CalculatorBatchConsumption> response = await calculatorClient.BatchComputeAsync(userAndUid, delta).ConfigureAwait(false);
|
||||
Response<CalculatorBatchConsumption> response;
|
||||
using (IServiceScope scope = scopeContext.ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
CalculateClient calculatorClient = scope.ServiceProvider.GetRequiredService<CalculateClient>();
|
||||
response = await calculatorClient.BatchComputeAsync(userAndUid, deltaOptions.Delta).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await SaveCultivationAsync(response.Data.Items.Single(), delta).ConfigureAwait(false))
|
||||
if (!await SaveCultivationAsync(response.Data.Items.Single(), deltaOptions).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
return;
|
||||
}
|
||||
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
scopeContext.InfoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
}
|
||||
|
||||
[Command("BatchCultivateCommand")]
|
||||
@@ -207,34 +203,35 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
return;
|
||||
}
|
||||
|
||||
if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid)
|
||||
if (await scopeContext.UserService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid)
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
scopeContext.InfoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
return;
|
||||
}
|
||||
|
||||
CultivatePromotionDeltaBatchDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaBatchDialog>().ConfigureAwait(false);
|
||||
(bool isOk, CalculatorAvatarPromotionDelta baseline) = await dialog.GetPromotionDeltaBaselineAsync().ConfigureAwait(false);
|
||||
CultivatePromotionDeltaBatchDialog dialog = await scopeContext.ContentDialogFactory
|
||||
.CreateInstanceAsync<CultivatePromotionDeltaBatchDialog>().ConfigureAwait(false);
|
||||
(bool isOk, CultivatePromotionDeltaOptions deltaOptions) = await dialog.GetPromotionDeltaBaselineAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(baseline.SkillList);
|
||||
ArgumentNullException.ThrowIfNull(baseline.Weapon);
|
||||
ArgumentNullException.ThrowIfNull(deltaOptions.Delta.SkillList);
|
||||
ArgumentNullException.ThrowIfNull(deltaOptions.Delta.Weapon);
|
||||
|
||||
ContentDialog progressDialog = await contentDialogFactory
|
||||
ContentDialog progressDialog = await scopeContext.ContentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyBatchCultivateProgressTitle)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
BatchCultivateResult result = default;
|
||||
using (await progressDialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
using (await progressDialog.BlockAsync(scopeContext.TaskContext).ConfigureAwait(false))
|
||||
{
|
||||
List<CalculatorAvatarPromotionDelta> deltas = [];
|
||||
foreach (AvatarView avatar in avatars)
|
||||
{
|
||||
if (!baseline.TryGetNonErrorCopy(avatar, out CalculatorAvatarPromotionDelta? copy))
|
||||
if (!deltaOptions.Delta.TryGetNonErrorCopy(avatar, out CalculatorAvatarPromotionDelta? copy))
|
||||
{
|
||||
++result.SkippedCount;
|
||||
continue;
|
||||
@@ -243,7 +240,12 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
deltas.Add(copy);
|
||||
}
|
||||
|
||||
Response<CalculatorBatchConsumption> response = await calculatorClient.BatchComputeAsync(userAndUid, deltas).ConfigureAwait(false);
|
||||
Response<CalculatorBatchConsumption> response;
|
||||
using (IServiceScope scope = scopeContext.ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
CalculateClient calculatorClient = scope.ServiceProvider.GetRequiredService<CalculateClient>();
|
||||
response = await calculatorClient.BatchComputeAsync(userAndUid, deltas).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
@@ -252,9 +254,8 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
|
||||
foreach ((CalculatorConsumption consumption, CalculatorAvatarPromotionDelta delta) in response.Data.Items.Zip(deltas))
|
||||
{
|
||||
if (!await SaveCultivationAsync(consumption, delta).ConfigureAwait(false))
|
||||
if (!await SaveCultivationAsync(consumption, new(delta, deltaOptions.Strategy)).ConfigureAwait(false))
|
||||
{
|
||||
result.Interrupted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -262,42 +263,70 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Interrupted)
|
||||
if (result.SkippedCount > 0)
|
||||
{
|
||||
infoBarService.Warning(SH.FormatViewModelCultivationBatchAddIncompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||
scopeContext.InfoBarService.Warning(SH.FormatViewModelCultivationBatchAddIncompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Success(SH.FormatViewModelCultivationBatchAddCompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||
scopeContext.InfoBarService.Success(SH.FormatViewModelCultivationBatchAddCompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> SaveCultivationAsync(CalculatorConsumption consumption, CalculatorAvatarPromotionDelta delta)
|
||||
/// <returns><see langword="true"/> if we can continue saving consumptions, otherwise <see langword="false"/>.</returns>
|
||||
private async ValueTask<bool> SaveCultivationAsync(CalculatorConsumption consumption, CultivatePromotionDeltaOptions options)
|
||||
{
|
||||
LevelInformation levelInformation = LevelInformation.From(delta);
|
||||
LevelInformation levelInformation = LevelInformation.From(options.Delta);
|
||||
|
||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||
bool avatarSaved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, delta.AvatarId, items, levelInformation)
|
||||
.ConfigureAwait(false);
|
||||
InputConsumption avatarInput = new()
|
||||
{
|
||||
Type = CultivateType.AvatarAndSkill,
|
||||
ItemId = options.Delta.AvatarId,
|
||||
Items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume),
|
||||
LevelInformation = levelInformation,
|
||||
Strategy = options.Strategy,
|
||||
};
|
||||
|
||||
ConsumptionSaveResultKind avatarSaveKind = await scopeContext.CultivationService.SaveConsumptionAsync(avatarInput).ConfigureAwait(false);
|
||||
|
||||
switch (avatarSaveKind)
|
||||
{
|
||||
case ConsumptionSaveResultKind.NoProject:
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
return false;
|
||||
case ConsumptionSaveResultKind.Skipped:
|
||||
scopeContext.InfoBarService.Information(SH.ViewModelCultivationConsumptionSaveSkippedHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.NoItem:
|
||||
scopeContext.InfoBarService.Information(SH.ViewModelCultivationConsumptionSaveNoItemHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.Added:
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(delta.Weapon);
|
||||
ArgumentNullException.ThrowIfNull(options.Delta.Weapon);
|
||||
|
||||
// Take a hot path if avatar is not saved.
|
||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.Weapon, delta.Weapon.Id, consumption.WeaponConsume.EmptyIfNull(), levelInformation)
|
||||
.ConfigureAwait(false);
|
||||
InputConsumption weaponInput = new()
|
||||
{
|
||||
Type = CultivateType.Weapon,
|
||||
ItemId = options.Delta.Weapon.Id,
|
||||
Items = consumption.WeaponConsume.EmptyIfNull(),
|
||||
LevelInformation = levelInformation,
|
||||
Strategy = options.Strategy,
|
||||
};
|
||||
|
||||
return avatarAndWeaponSaved;
|
||||
ConsumptionSaveResultKind weaponSaveKind = await scopeContext.CultivationService.SaveConsumptionAsync(weaponInput).ConfigureAwait(false);
|
||||
|
||||
return weaponSaveKind is not ConsumptionSaveResultKind.NoProject;
|
||||
}
|
||||
catch (HutaoException ex)
|
||||
{
|
||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||
scopeContext.InfoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("ExportToTextCommand")]
|
||||
@@ -308,13 +337,13 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
return;
|
||||
}
|
||||
|
||||
if (clipboardProvider.SetText(AvatarViewTextTemplating.GetTemplatedText(avatar)))
|
||||
if (scopeContext.ClipboardProvider.SetText(AvatarViewTextTemplating.GetTemplatedText(avatar)))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelAvatatPropertyExportTextSuccess);
|
||||
scopeContext.InfoBarService.Success(SH.ViewModelAvatatPropertyExportTextSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelAvatatPropertyExportTextError);
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelAvatatPropertyExportTextError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DataTransfer;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Service.AvatarInfo;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Service.User;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AvatarPropertyViewModelScopeContext
|
||||
{
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private readonly ICultivationService cultivationService;
|
||||
private readonly IAvatarInfoService avatarInfoService;
|
||||
private readonly IClipboardProvider clipboardProvider;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IUserService userService;
|
||||
|
||||
public IContentDialogFactory ContentDialogFactory { get => contentDialogFactory; }
|
||||
|
||||
public IServiceScopeFactory ServiceScopeFactory { get => serviceScopeFactory; }
|
||||
|
||||
public ICultivationService CultivationService { get => cultivationService; }
|
||||
|
||||
public IAvatarInfoService AvatarInfoService { get => avatarInfoService; }
|
||||
|
||||
public IClipboardProvider ClipboardProvider { get => clipboardProvider; }
|
||||
|
||||
public IInfoBarService InfoBarService { get => infoBarService; }
|
||||
|
||||
public ITaskContext TaskContext { get => taskContext; }
|
||||
|
||||
public IUserService UserService { get => userService; }
|
||||
}
|
||||
@@ -7,5 +7,4 @@ internal struct BatchCultivateResult
|
||||
{
|
||||
public int SucceedCount;
|
||||
public int SkippedCount;
|
||||
public bool Interrupted;
|
||||
}
|
||||
@@ -325,7 +325,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
async ValueTask UpdateGameAccountsViewAsync()
|
||||
{
|
||||
gameAccountFilter = new(SelectedScheme?.GetSchemeType());
|
||||
ObservableReorderableDbCollection<GameAccount> accounts = gameService.GameAccountCollection;
|
||||
ObservableReorderableDbCollection<GameAccount> accounts = await gameService.GetGameAccountCollectionAsync().ConfigureAwait(false);
|
||||
AdvancedCollectionView<GameAccount> accountsView = new(accounts) { Filter = gameAccountFilter.Filter };
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
@@ -43,13 +43,14 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
|
||||
protected override async Task LoadAsync()
|
||||
{
|
||||
LaunchScheme? scheme = launchGameShared.GetCurrentLaunchSchemeFromConfigFile();
|
||||
ObservableCollection<GameAccount> accounts = gameService.GameAccountCollection;
|
||||
ObservableCollection<GameAccount> accounts = await gameService.GetGameAccountCollectionAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
if (scheme is not null)
|
||||
{
|
||||
// Try set to the current account.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SelectedGameAccount ??= gameService.DetectCurrentGameAccount(scheme);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Picker;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Service.GachaLog;
|
||||
|
||||
@@ -85,7 +85,7 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
AdvancedCollectionView<SpiralAbyssView> spiralAbyssEntries = new(collection);
|
||||
AdvancedCollectionView<SpiralAbyssView> spiralAbyssEntries = collection.ToAdvancedCollectionView();
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SpiralAbyssEntries = spiralAbyssEntries;
|
||||
|
||||
@@ -24,7 +24,6 @@ using Snap.Hutao.Web.Response;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
|
||||
using CalculateBatchConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.BatchConsumption;
|
||||
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
|
||||
|
||||
@@ -43,8 +42,8 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IHutaoSpiralAbyssStatisticsCache hutaoCache;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly CalculateClient calculateClient;
|
||||
private readonly IUserService userService;
|
||||
|
||||
private AdvancedCollectionView<Avatar>? avatars;
|
||||
@@ -109,7 +108,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
|
||||
|
||||
using (await EnterCriticalSectionAsync().ConfigureAwait(false))
|
||||
{
|
||||
AdvancedCollectionView<Avatar> avatarsView = new(list);
|
||||
AdvancedCollectionView<Avatar> avatarsView = list.ToAdvancedCollectionView();
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Avatars = avatarsView;
|
||||
@@ -173,16 +172,19 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
|
||||
|
||||
CalculableOptions options = new(avatar.ToCalculable(), null);
|
||||
CultivatePromotionDeltaDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CalculateAvatarPromotionDelta delta) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
(bool isOk, CultivatePromotionDeltaOptions deltaOptions) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Response<CalculateBatchConsumption> response = await calculateClient
|
||||
.BatchComputeAsync(userAndUid, delta)
|
||||
.ConfigureAwait(false);
|
||||
Response<CalculateBatchConsumption> response;
|
||||
using (IServiceScope scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
CalculateClient calculateClient = scope.ServiceProvider.GetRequiredService<CalculateClient>();
|
||||
response = await calculateClient.BatchComputeAsync(userAndUid, deltaOptions.Delta).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
@@ -190,20 +192,32 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
|
||||
}
|
||||
|
||||
CalculateBatchConsumption batchConsumption = response.Data;
|
||||
LevelInformation levelInformation = LevelInformation.From(delta);
|
||||
LevelInformation levelInformation = LevelInformation.From(deltaOptions.Delta);
|
||||
try
|
||||
{
|
||||
bool saved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, batchConsumption.OverallConsume, levelInformation)
|
||||
.ConfigureAwait(false);
|
||||
InputConsumption input = new()
|
||||
{
|
||||
Type = CultivateType.AvatarAndSkill,
|
||||
ItemId = avatar.Id,
|
||||
Items = batchConsumption.OverallConsume,
|
||||
LevelInformation = levelInformation,
|
||||
Strategy = deltaOptions.Strategy,
|
||||
};
|
||||
|
||||
if (saved)
|
||||
switch (await cultivationService.SaveConsumptionAsync(input).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
case ConsumptionSaveResultKind.NoProject:
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.Skipped:
|
||||
infoBarService.Information(SH.ViewModelCultivationConsumptionSaveSkippedHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.NoItem:
|
||||
infoBarService.Information(SH.ViewModelCultivationConsumptionSaveNoItemHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.Added:
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (HutaoException ex)
|
||||
|
||||
@@ -68,7 +68,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel
|
||||
|
||||
using (await EnterCriticalSectionAsync().ConfigureAwait(false))
|
||||
{
|
||||
AdvancedCollectionView<Monster> monstersView = new(ordered);
|
||||
AdvancedCollectionView<Monster> monstersView = ordered.ToAdvancedCollectionView();
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Monsters = monstersView;
|
||||
|
||||
@@ -24,7 +24,6 @@ using Snap.Hutao.Web.Response;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
|
||||
using CalculateBatchConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.BatchConsumption;
|
||||
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
|
||||
|
||||
@@ -38,11 +37,11 @@ namespace Snap.Hutao.ViewModel.Wiki;
|
||||
internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
|
||||
{
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly CalculateClient calculateClient;
|
||||
private readonly ICultivationService cultivationService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IHutaoSpiralAbyssStatisticsCache hutaoCache;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IUserService userService;
|
||||
|
||||
@@ -108,7 +107,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
|
||||
|
||||
using (await EnterCriticalSectionAsync().ConfigureAwait(false))
|
||||
{
|
||||
AdvancedCollectionView<Weapon> weaponsView = new(list);
|
||||
AdvancedCollectionView<Weapon> weaponsView = list.ToAdvancedCollectionView();
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
@@ -168,16 +167,19 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
|
||||
|
||||
CalculableOptions options = new(null, weapon.ToCalculable());
|
||||
CultivatePromotionDeltaDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CalculateAvatarPromotionDelta delta) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
(bool isOk, CultivatePromotionDeltaOptions deltaOptions) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Response<CalculateBatchConsumption> response = await calculateClient
|
||||
.BatchComputeAsync(userAndUid, delta)
|
||||
.ConfigureAwait(false);
|
||||
Response<CalculateBatchConsumption> response;
|
||||
using (IServiceScope scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
CalculateClient calculateClient = scope.ServiceProvider.GetRequiredService<CalculateClient>();
|
||||
response = await calculateClient.BatchComputeAsync(userAndUid, deltaOptions.Delta).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
@@ -185,20 +187,32 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
|
||||
}
|
||||
|
||||
CalculateBatchConsumption batchConsumption = response.Data;
|
||||
LevelInformation levelInformation = LevelInformation.From(delta);
|
||||
LevelInformation levelInformation = LevelInformation.From(deltaOptions.Delta);
|
||||
try
|
||||
{
|
||||
bool saved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.Weapon, weapon.Id, batchConsumption.OverallConsume, levelInformation)
|
||||
.ConfigureAwait(false);
|
||||
InputConsumption input = new()
|
||||
{
|
||||
Type = CultivateType.Weapon,
|
||||
ItemId = weapon.Id,
|
||||
Items = batchConsumption.OverallConsume,
|
||||
LevelInformation = levelInformation,
|
||||
Strategy = deltaOptions.Strategy,
|
||||
};
|
||||
|
||||
if (saved)
|
||||
switch (await cultivationService.SaveConsumptionAsync(input).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
case ConsumptionSaveResultKind.NoProject:
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.Skipped:
|
||||
infoBarService.Information(SH.ViewModelCultivationConsumptionSaveSkippedHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.NoItem:
|
||||
infoBarService.Information(SH.ViewModelCultivationConsumptionSaveNoItemHint);
|
||||
break;
|
||||
case ConsumptionSaveResultKind.Added:
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (HutaoException ex)
|
||||
|
||||
Reference in New Issue
Block a user