mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
remove visual transition gap in gacha log initialization
This commit is contained in:
@@ -119,8 +119,8 @@ internal static class CoreEnvironment
|
||||
{
|
||||
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
#if RELEASE
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
#else
|
||||
// 使得迁移能正常生成
|
||||
string folderName = "Hutao";
|
||||
|
||||
@@ -149,7 +149,7 @@ internal static class Activation
|
||||
|
||||
Ioc.Default
|
||||
.GetRequiredService<IMetadataService>()
|
||||
.ImplictAs<IMetadataInitializer>()?
|
||||
.ImplictAs<IMetadataServiceInitialization>()?
|
||||
.InitializeInternalAsync()
|
||||
.SafeForget();
|
||||
}
|
||||
|
||||
@@ -6,9 +6,30 @@ using System.Collections.Concurrent;
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// 并发<see cref="CancellationTokenSource"/>
|
||||
/// 无区分项的并发<see cref="CancellationTokenSource"/>
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA1001")]
|
||||
internal class ConcurrentCancellationTokenSource
|
||||
{
|
||||
private CancellationTokenSource source = new();
|
||||
|
||||
/// <summary>
|
||||
/// 注册取消令牌
|
||||
/// </summary>
|
||||
/// <returns>取消令牌</returns>
|
||||
public CancellationToken Register()
|
||||
{
|
||||
source.Cancel();
|
||||
source = new();
|
||||
return source.Token;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 有区分项的并发<see cref="CancellationTokenSource"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">项类型</typeparam>
|
||||
[SuppressMessage("", "SA1402")]
|
||||
internal class ConcurrentCancellationTokenSource<TItem>
|
||||
where TItem : notnull
|
||||
{
|
||||
@@ -17,7 +38,7 @@ internal class ConcurrentCancellationTokenSource<TItem>
|
||||
/// <summary>
|
||||
/// 为某个项注册取消令牌
|
||||
/// </summary>
|
||||
/// <param name="item">项</param>
|
||||
/// <param name="item">区分项</param>
|
||||
/// <returns>取消令牌</returns>
|
||||
public CancellationToken Register(TItem item)
|
||||
{
|
||||
@@ -28,4 +49,4 @@ internal class ConcurrentCancellationTokenSource<TItem>
|
||||
|
||||
return waitingItems.GetOrAdd(item, new CancellationTokenSource()).Token;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||
|
||||
@@ -25,7 +24,7 @@ public class CultivateItem : ObservableObject
|
||||
Inner = inner;
|
||||
Entity = entity;
|
||||
isFinished = Entity.IsFinished;
|
||||
IsToday = CultivateItemHelper.IsTodaysMaterial(inner.Id, DateTimeOffset.Now);
|
||||
IsToday = inner.IsTodaysItem();
|
||||
|
||||
FinishStateCommand = new RelayCommand(FlipIsFinished);
|
||||
}
|
||||
@@ -55,7 +54,6 @@ public class CultivateItem : ObservableObject
|
||||
if (SetProperty(ref isFinished, value))
|
||||
{
|
||||
Entity.IsFinished = value;
|
||||
Ioc.Default.GetRequiredService<ICultivationService>().SaveCultivateItem(Entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品帮助类
|
||||
/// </summary>
|
||||
public static class CultivateItemHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否为当日物品
|
||||
/// </summary>
|
||||
/// <param name="itemId">材料Id</param>
|
||||
/// <param name="now">时间</param>
|
||||
/// <returns>是否为当日物品</returns>
|
||||
public static bool IsTodaysMaterial(int itemId, DateTimeOffset now)
|
||||
{
|
||||
DateTimeOffset utcNow = now.ToUniversalTime();
|
||||
utcNow = utcNow.AddHours(4);
|
||||
DayOfWeek dayOfWeek = utcNow.DayOfWeek;
|
||||
|
||||
return dayOfWeek switch
|
||||
{
|
||||
DayOfWeek.Monday or DayOfWeek.Thursday => itemId switch
|
||||
{
|
||||
104301 or 104302 or 104303 => true, // 「自由」
|
||||
104310 or 104311 or 104312 => true, // 「繁荣」
|
||||
104320 or 104321 or 104322 => true, // 「浮世」
|
||||
104329 or 104330 or 104331 => true, // 「诤言」
|
||||
114001 or 114002 or 114003 or 114004 => true, // 高塔孤王
|
||||
114013 or 114014 or 114015 or 114016 => true, // 孤云寒林
|
||||
114025 or 114026 or 114027 or 114028 => true, // 远海夷地
|
||||
114037 or 114038 or 114039 or 114040 => true, // 谧林涓露
|
||||
_ => false,
|
||||
},
|
||||
DayOfWeek.Tuesday or DayOfWeek.Friday => itemId switch
|
||||
{
|
||||
104304 or 104305 or 104306 => true, // 「抗争」
|
||||
104313 or 104314 or 104315 => true, // 「勤劳」
|
||||
104323 or 104324 or 104325 => true, // 「风雅」
|
||||
104332 or 104333 or 104334 => true, // 「巧思」
|
||||
114005 or 114006 or 114007 or 114008 => true, // 凛风奔狼
|
||||
114017 or 114018 or 114019 or 114020 => true, // 雾海云间
|
||||
114029 or 114030 or 114031 or 114032 => true, // 鸣神御灵
|
||||
114041 or 114042 or 114043 or 114044 => true, // 绿洲花园
|
||||
_ => false,
|
||||
},
|
||||
DayOfWeek.Wednesday or DayOfWeek.Saturday => itemId switch
|
||||
{
|
||||
104307 or 104308 or 104309 => true, // 「诗文」
|
||||
104316 or 104317 or 104318 => true, // 「黄金」
|
||||
104326 or 104327 or 104328 => true, // 「天光」
|
||||
104335 or 104336 or 104337 => true, // 「笃行」
|
||||
114009 or 114010 or 114011 or 114012 => true, // 狮牙斗士
|
||||
114021 or 114022 or 114023 or 114024 => true, // 漆黑陨铁
|
||||
114033 or 114034 or 114035 or 114036 => true, // 今昔剧画
|
||||
114045 or 114046 or 114047 or 114048 => true, // 谧林涓露
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,47 +13,47 @@ public enum MaterialType
|
||||
MATERIAL_FOOD = 1,
|
||||
MATERIAL_QUEST = 2,
|
||||
MATERIAL_EXCHANGE = 4,
|
||||
MATERIAL_CONSUME,
|
||||
MATERIAL_EXP_FRUIT,
|
||||
MATERIAL_AVATAR,
|
||||
MATERIAL_ADSORBATE,
|
||||
MATERIAL_CRICKET,
|
||||
MATERIAL_ELEM_CRYSTAL,
|
||||
MATERIAL_WEAPON_EXP_STONE,
|
||||
MATERIAL_CHEST,
|
||||
MATERIAL_RELIQUARY_MATERIAL,
|
||||
MATERIAL_AVATAR_MATERIAL,
|
||||
MATERIAL_NOTICE_ADD_HP,
|
||||
MATERIAL_SEA_LAMP,
|
||||
MATERIAL_SELECTABLE_CHEST,
|
||||
MATERIAL_FLYCLOAK,
|
||||
MATERIAL_NAMECARD,
|
||||
MATERIAL_TALENT,
|
||||
MATERIAL_WIDGET,
|
||||
MATERIAL_CHEST_BATCH_USE,
|
||||
MATERIAL_FAKE_ABSORBATE,
|
||||
MATERIAL_CONSUME_BATCH_USE,
|
||||
MATERIAL_WOOD,
|
||||
MATERIAL_CONSUME = 5,
|
||||
MATERIAL_EXP_FRUIT = 6,
|
||||
MATERIAL_AVATAR = 7,
|
||||
MATERIAL_ADSORBATE = 8,
|
||||
MATERIAL_CRICKET = 9,
|
||||
MATERIAL_ELEM_CRYSTAL = 10,
|
||||
MATERIAL_WEAPON_EXP_STONE = 11,
|
||||
MATERIAL_CHEST = 12,
|
||||
MATERIAL_RELIQUARY_MATERIAL = 13,
|
||||
MATERIAL_AVATAR_MATERIAL = 14,
|
||||
MATERIAL_NOTICE_ADD_HP = 15,
|
||||
MATERIAL_SEA_LAMP = 16,
|
||||
MATERIAL_SELECTABLE_CHEST = 17,
|
||||
MATERIAL_FLYCLOAK = 18,
|
||||
MATERIAL_NAMECARD = 19,
|
||||
MATERIAL_TALENT = 20,
|
||||
MATERIAL_WIDGET = 21,
|
||||
MATERIAL_CHEST_BATCH_USE = 22,
|
||||
MATERIAL_FAKE_ABSORBATE = 23,
|
||||
MATERIAL_CONSUME_BATCH_USE = 24,
|
||||
MATERIAL_WOOD = 25,
|
||||
MATERIAL_FURNITURE_FORMULA = 27,
|
||||
MATERIAL_CHANNELLER_SLAB_BUFF,
|
||||
MATERIAL_FURNITURE_SUITE_FORMULA,
|
||||
MATERIAL_COSTUME,
|
||||
MATERIAL_HOME_SEED,
|
||||
MATERIAL_FISH_BAIT,
|
||||
MATERIAL_FISH_ROD,
|
||||
MATERIAL_SUMO_BUFF, // never appear
|
||||
MATERIAL_FIREWORKS,
|
||||
MATERIAL_BGM,
|
||||
MATERIAL_SPICE_FOOD,
|
||||
MATERIAL_ACTIVITY_ROBOT,
|
||||
MATERIAL_ACTIVITY_GEAR,
|
||||
MATERIAL_ACTIVITY_JIGSAW,
|
||||
MATERIAL_ARANARA,
|
||||
MATERIAL_GCG_CARD,
|
||||
MATERIAL_GCG_CARD_FACE, // 影幻卡面
|
||||
MATERIAL_GCG_CARD_BACK,
|
||||
MATERIAL_GCG_FIELD,
|
||||
MATERIAL_DESHRET_MANUAL,
|
||||
MATERIAL_RENAME_ITEM,
|
||||
MATERIAL_GCG_EXCHANGE_ITEM,
|
||||
MATERIAL_CHANNELLER_SLAB_BUFF = 28,
|
||||
MATERIAL_FURNITURE_SUITE_FORMULA = 29,
|
||||
MATERIAL_COSTUME = 30,
|
||||
MATERIAL_HOME_SEED = 31,
|
||||
MATERIAL_FISH_BAIT = 32,
|
||||
MATERIAL_FISH_ROD = 33,
|
||||
MATERIAL_SUMO_BUFF = 34, // never appear
|
||||
MATERIAL_FIREWORKS = 35,
|
||||
MATERIAL_BGM = 36,
|
||||
MATERIAL_SPICE_FOOD = 37,
|
||||
MATERIAL_ACTIVITY_ROBOT = 38,
|
||||
MATERIAL_ACTIVITY_GEAR = 39,
|
||||
MATERIAL_ACTIVITY_JIGSAW = 40,
|
||||
MATERIAL_ARANARA = 41,
|
||||
MATERIAL_GCG_CARD = 42,
|
||||
MATERIAL_GCG_CARD_FACE = 43, // 影幻卡面
|
||||
MATERIAL_GCG_CARD_BACK = 44,
|
||||
MATERIAL_GCG_FIELD = 45,
|
||||
MATERIAL_DESHRET_MANUAL = 46,
|
||||
MATERIAL_RENAME_ITEM = 47,
|
||||
MATERIAL_GCG_EXCHANGE_ITEM = 48,
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
@@ -11,6 +12,42 @@ namespace Snap.Hutao.Model.Metadata;
|
||||
/// </summary>
|
||||
public class Material
|
||||
{
|
||||
private static readonly ImmutableHashSet<MaterialId> MondayThursdayItems = new HashSet<MaterialId>
|
||||
{
|
||||
104301, 104302, 104303, // 「自由」
|
||||
104310, 104311, 104312, // 「繁荣」
|
||||
104320, 104321, 104322, // 「浮世」
|
||||
104329, 104330, 104331, // 「诤言」
|
||||
114001, 114002, 114003, 114004, // 高塔孤王
|
||||
114013, 114014, 114015, 114016, // 孤云寒林
|
||||
114025, 114026, 114027, 114028, // 远海夷地
|
||||
114037, 114038, 114039, 114040, // 谧林涓露
|
||||
}.ToImmutableHashSet();
|
||||
|
||||
private static readonly ImmutableHashSet<MaterialId> TuesdayFridayItems = new HashSet<MaterialId>
|
||||
{
|
||||
104304, 104305, 104306, // 「抗争」
|
||||
104313, 104314, 104315, // 「勤劳」
|
||||
104323, 104324, 104325, // 「风雅」
|
||||
104332, 104333, 104334, // 「巧思」
|
||||
114005, 114006, 114007, 114008, // 凛风奔狼
|
||||
114017, 114018, 114019, 114020, // 雾海云间
|
||||
114029, 114030, 114031, 114032, // 鸣神御灵
|
||||
114041, 114042, 114043, 114044, // 绿洲花园
|
||||
}.ToImmutableHashSet();
|
||||
|
||||
private static readonly ImmutableHashSet<MaterialId> WednesdaySaturdayItems = new HashSet<MaterialId>
|
||||
{
|
||||
104307, 104308, 104309, // 「诗文」
|
||||
104316, 104317, 104318, // 「黄金」
|
||||
104326, 104327, 104328, // 「天光」
|
||||
104335, 104336, 104337, // 「笃行」
|
||||
114009, 114010, 114011, 114012, // 狮牙斗士
|
||||
114021, 114022, 114023, 114024, // 漆黑陨铁
|
||||
114033, 114034, 114035, 114036, // 今昔剧画
|
||||
114045, 114046, 114047, 114048, // 谧林涓露
|
||||
}.ToImmutableHashSet();
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
@@ -89,4 +126,21 @@ public class Material
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否为当日物品
|
||||
/// O(1) 操作
|
||||
/// </summary>
|
||||
/// <param name="treatSundayAsTrue">星期日视为当日材料</param>
|
||||
/// <returns>是否为当日物品</returns>
|
||||
public bool IsTodaysItem(bool treatSundayAsTrue = false)
|
||||
{
|
||||
return DateTimeOffset.UtcNow.AddHours(4).DayOfWeek switch
|
||||
{
|
||||
DayOfWeek.Monday or DayOfWeek.Thursday => MondayThursdayItems.Contains(Id),
|
||||
DayOfWeek.Tuesday or DayOfWeek.Friday => TuesdayFridayItems.Contains(Id),
|
||||
DayOfWeek.Wednesday or DayOfWeek.Saturday => WednesdaySaturdayItems.Contains(Id),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.3.12.0" />
|
||||
Version="1.3.13.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -5,13 +5,16 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using System.Collections.ObjectModel;
|
||||
using BindingCultivateEntry = Snap.Hutao.Model.Binding.Cultivation.CultivateEntry;
|
||||
using BindingCultivateItem = Snap.Hutao.Model.Binding.Cultivation.CultivateItem;
|
||||
using BindingInventoryItem = Snap.Hutao.Model.Binding.Inventory.InventoryItem;
|
||||
using BindingStatisticsItem = Snap.Hutao.Model.Binding.Cultivation.StatisticsCultivateItem;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
@@ -129,22 +132,21 @@ internal class CultivationService : ICultivationService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ObservableCollection<BindingCultivateEntry>> GetCultivateEntriesAsync(
|
||||
CultivateProject cultivateProject,
|
||||
List<Model.Metadata.Material> materials,
|
||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap,
|
||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap)
|
||||
public async Task<ObservableCollection<BindingCultivateEntry>> GetCultivateEntriesAsync(CultivateProject cultivateProject)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
IMetadataService metadataService = scope.ServiceProvider.GetRequiredService<IMetadataService>();
|
||||
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
List<Model.Metadata.Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
|
||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
|
||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
|
||||
|
||||
List<BindingCultivateEntry> results = new();
|
||||
List<CultivateEntry> entries = await appDbContext.CultivateEntries
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.Where(e => e.ProjectId == cultivateProject.InnerId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -153,13 +155,8 @@ internal class CultivationService : ICultivationService
|
||||
Guid entryId = entry.InnerId;
|
||||
|
||||
List<BindingCultivateItem> resultItems = new();
|
||||
List<CultivateItem> items = await appDbContext.CultivateItems
|
||||
.Where(i => i.EntryId == entryId)
|
||||
.OrderBy(i => i.ItemId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (CultivateItem item in items)
|
||||
foreach (CultivateItem item in await GetEntryItemsAsync(appDbContext, entryId).ConfigureAwait(false))
|
||||
{
|
||||
resultItems.Add(new(materials.Single(m => m.Id == item.ItemId), item));
|
||||
}
|
||||
@@ -174,71 +171,64 @@ internal class CultivationService : ICultivationService
|
||||
results.Add(new(entry, itemBase, resultItems));
|
||||
}
|
||||
|
||||
return new(results.OrderByDescending(e => e.Items.Any(i => i.IsToday)));
|
||||
return results
|
||||
.OrderByDescending(e => e.Items.Any(i => i.IsToday))
|
||||
.ToObservableCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<List<Model.Binding.Cultivation.StatisticsCultivateItem>> GetStatisticsCultivateItemsAsync(CultivateProject cultivateProject, List<Model.Metadata.Material> materials)
|
||||
public async Task<ObservableCollection<BindingStatisticsItem>> GetStatisticsCultivateItemCollectionAsync(CultivateProject cultivateProject, CancellationToken token)
|
||||
{
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
List<BindingStatisticsItem> resultItems = new();
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
List<Model.Metadata.Material> materials = await scope.ServiceProvider
|
||||
.GetRequiredService<IMetadataService>()
|
||||
.GetMaterialsAsync(default)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
|
||||
List<Model.Binding.Cultivation.StatisticsCultivateItem> resultItems = new();
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
List<CultivateEntry> entries = await appDbContext.CultivateEntries
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (CultivateEntry entry in entries)
|
||||
foreach (CultivateEntry entry in await GetProjectEntriesAsync(appDbContext, projectId).ConfigureAwait(false))
|
||||
{
|
||||
Guid entryId = entry.InnerId;
|
||||
|
||||
List<CultivateItem> items = await appDbContext.CultivateItems
|
||||
.AsNoTracking()
|
||||
.Where(i => i.EntryId == entryId)
|
||||
.OrderBy(i => i.ItemId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (CultivateItem item in items)
|
||||
foreach (CultivateItem item in await GetEntryItemsAsync(appDbContext, entry.InnerId).ConfigureAwait(false))
|
||||
{
|
||||
if (item.IsFinished)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resultItems.SingleOrDefault(i => i.Inner.Id == item.ItemId) is Model.Binding.Cultivation.StatisticsCultivateItem inPlaceItem)
|
||||
if (resultItems.SingleOrDefault(i => i.Inner.Id == item.ItemId) is BindingStatisticsItem existedItem)
|
||||
{
|
||||
inPlaceItem.Count += item.Count;
|
||||
existedItem.Count += item.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultItems.Add(new(materials.Single(m => m.Id == item.ItemId), item));
|
||||
resultItems.Add(new(materials!.Single(m => m.Id == item.ItemId), item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<InventoryItem> inventoryItems = await appDbContext.InventoryItems
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (InventoryItem inventoryItem in inventoryItems)
|
||||
foreach (InventoryItem inventoryItem in await GetProjectInventoryAsync(appDbContext, projectId).ConfigureAwait(false))
|
||||
{
|
||||
if (resultItems.SingleOrDefault(i => i.Inner.Id == inventoryItem.ItemId) is Model.Binding.Cultivation.StatisticsCultivateItem inPlaceItem)
|
||||
if (resultItems.SingleOrDefault(i => i.Inner.Id == inventoryItem.ItemId) is BindingStatisticsItem existedItem)
|
||||
{
|
||||
inPlaceItem.TotalCount += inventoryItem.Count;
|
||||
existedItem.TotalCount += inventoryItem.Count;
|
||||
}
|
||||
}
|
||||
|
||||
return resultItems.OrderByDescending(i => i.Count).ToList();
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
|
||||
return resultItems.OrderByDescending(i => i.Count).ToObservableCollection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,9 +236,11 @@ internal class CultivationService : ICultivationService
|
||||
public async Task RemoveCultivateEntryAsync(Guid entryId)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
IEnumerable<CultivateItem> removed;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
removed = await GetEntryItemsAsync(appDbContext, entryId).ConfigureAwait(false);
|
||||
await appDbContext.CultivateEntries.Where(i => i.InnerId == entryId).ExecuteDeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -309,4 +301,29 @@ internal class CultivationService : ICultivationService
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Task<List<InventoryItem>> GetProjectInventoryAsync(AppDbContext appDbContext, Guid projectId)
|
||||
{
|
||||
return appDbContext.InventoryItems
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
private static Task<List<CultivateEntry>> GetProjectEntriesAsync(AppDbContext appDbContext, Guid projectId)
|
||||
{
|
||||
return appDbContext.CultivateEntries
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
private static Task<List<CultivateItem>> GetEntryItemsAsync(AppDbContext appDbContext, Guid entryId)
|
||||
{
|
||||
return appDbContext.CultivateItems
|
||||
.AsNoTracking()
|
||||
.Where(i => i.EntryId == entryId)
|
||||
.OrderBy(i => i.ItemId)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,8 @@ internal interface ICultivationService
|
||||
/// 获取绑定用的养成列表
|
||||
/// </summary>
|
||||
/// <param name="cultivateProject">养成计划</param>
|
||||
/// <param name="materials">材料</param>
|
||||
/// <param name="idAvatarMap">Id角色映射</param>
|
||||
/// <param name="idWeaponMap">Id武器映射</param>
|
||||
/// <returns>绑定用的养成列表</returns>
|
||||
Task<ObservableCollection<Model.Binding.Cultivation.CultivateEntry>> GetCultivateEntriesAsync(CultivateProject cultivateProject, List<Material> materials, Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap, Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap);
|
||||
Task<ObservableCollection<Model.Binding.Cultivation.CultivateEntry>> GetCultivateEntriesAsync(CultivateProject cultivateProject);
|
||||
|
||||
/// <summary>
|
||||
/// 获取物品列表
|
||||
@@ -48,9 +45,9 @@ internal interface ICultivationService
|
||||
/// 异步获取统计物品列表
|
||||
/// </summary>
|
||||
/// <param name="cultivateProject">养成计划</param>
|
||||
/// <param name="materials">元数据</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>统计物品列表</returns>
|
||||
Task<List<StatisticsCultivateItem>> GetStatisticsCultivateItemsAsync(CultivateProject cultivateProject, List<Material> materials);
|
||||
Task<ObservableCollection<StatisticsCultivateItem>> GetStatisticsCultivateItemCollectionAsync(CultivateProject cultivateProject, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 删除养成清单
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Service.Metadata;
|
||||
/// <summary>
|
||||
/// 指示该类为元数据初始化器
|
||||
/// </summary>
|
||||
public interface IMetadataInitializer
|
||||
public interface IMetadataServiceInitialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步初始化元数据
|
||||
@@ -19,7 +19,7 @@ namespace Snap.Hutao.Service.Metadata;
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton, typeof(IMetadataService))]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal partial class MetadataService : IMetadataService, IMetadataInitializer
|
||||
internal partial class MetadataService : IMetadataService, IMetadataServiceInitialization
|
||||
{
|
||||
private const string MetaFileName = "Meta.json";
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
|
||||
<Grid Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Grid Visibility="{Binding Projects.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
|
||||
<Rectangle
|
||||
@@ -52,54 +53,6 @@
|
||||
<Pivot>
|
||||
<Pivot.RightHeader>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
<AppBarButton
|
||||
Command="{Binding UpdateStatisticsItemsCommand}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="材料统计">
|
||||
<AppBarButton.Flyout>
|
||||
<Flyout Placement="Bottom">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
|
||||
<Setter Property="MaxHeight" Value="480"/>
|
||||
<Setter Property="Padding" Value="0,2,0,2"/>
|
||||
<Setter Property="Background" Value="{ThemeResource FlyoutPresenterBackground}"/>
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<ItemsControl Margin="16,0,16,16" ItemsSource="{Binding StatisticsItems}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,16,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Margin="16,0,4,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding CountFormatted}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Flyout>
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>
|
||||
<AppBarSeparator/>
|
||||
<AppBarElementContainer>
|
||||
<ComboBox
|
||||
Height="36"
|
||||
@@ -127,149 +80,195 @@
|
||||
|
||||
<PivotItem Header="材料清单">
|
||||
<Grid>
|
||||
<cwucont:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="320"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding CultivateEntries}"
|
||||
SelectionMode="None"
|
||||
Visibility="{Binding CultivateEntries.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
|
||||
<cwucont:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="8">
|
||||
<Pivot Visibility="{Binding CultivateEntries.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
|
||||
<PivotItem Header="材料统计">
|
||||
<cwucont:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="320"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding StatisticsItems}"
|
||||
SelectionMode="None">
|
||||
<cwucont:AdaptiveGridView.Resources>
|
||||
<x:Double x:Key="GridViewItemMinHeight">0</x:Double>
|
||||
</cwucont:AdaptiveGridView.Resources>
|
||||
<cwucont:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Width="48"
|
||||
Height="48"
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"/>
|
||||
<StackPanel
|
||||
x:Name="ButtonPanel"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
Visibility="Collapsed">
|
||||
<Button
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="8,0,0,0"
|
||||
Command="{Binding Path=DataContext.RemoveEntryCommand, Source={StaticResource BindingProxy}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content=""
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
ToolTipService.ToolTip="删除清单"/>
|
||||
</StackPanel>
|
||||
Margin="16,0,4,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding CountFormatted}"/>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Row="1" Height="240">
|
||||
<ItemsControl Margin="8,0,8,8" ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<shvc:ItemIcon
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="24"
|
||||
Glyph=""
|
||||
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
Margin="6,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding FinishStateCommand}">
|
||||
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
||||
</DataTemplate>
|
||||
</cwucont:AdaptiveGridView.ItemTemplate>
|
||||
</cwucont:AdaptiveGridView>
|
||||
</PivotItem>
|
||||
<PivotItem Header="养成物品">
|
||||
<cwucont:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="320"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding CultivateEntries}"
|
||||
SelectionMode="None">
|
||||
<cwucont:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Width="48"
|
||||
Height="48"
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"/>
|
||||
<StackPanel
|
||||
x:Name="ButtonPanel"
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
Visibility="Collapsed">
|
||||
<Button
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="8,0,0,0"
|
||||
Command="{Binding Path=DataContext.RemoveEntryCommand, Source={StaticResource BindingProxy}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content=""
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
ToolTipService.ToolTip="删除清单"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Row="1" Height="240">
|
||||
<ItemsControl Margin="8,0,8,8" ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
<Grid>
|
||||
<shvc:ItemIcon
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="24"
|
||||
Glyph=""
|
||||
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Entity.Count}"/>
|
||||
Height="32"
|
||||
Margin="6,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding Path=DataContext.FinishStateCommand, Source={StaticResource BindingProxy}}"
|
||||
CommandParameter="{Binding}">
|
||||
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Entity.Count}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Visible</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Visible</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</Grid.Resources>
|
||||
|
||||
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</Grid.Resources>
|
||||
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</cwucont:AdaptiveGridView.ItemTemplate>
|
||||
</cwucont:AdaptiveGridView>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</cwucont:AdaptiveGridView.ItemTemplate>
|
||||
</cwucont:AdaptiveGridView>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
@@ -305,7 +304,6 @@
|
||||
</wsc:SettingsGroup>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</PivotItem>
|
||||
<PivotItem Header="背包物品">
|
||||
<cwucont:AdaptiveGridView
|
||||
|
||||
@@ -24,11 +24,13 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly ILogger<CultivationViewModel> logger;
|
||||
|
||||
private readonly ConcurrentCancellationTokenSource statisticsCancellationTokenSource = new();
|
||||
|
||||
private ObservableCollection<CultivateProject>? projects;
|
||||
private CultivateProject? selectedProject;
|
||||
private List<Model.Binding.Inventory.InventoryItem>? inventoryItems;
|
||||
private ObservableCollection<Model.Binding.Cultivation.CultivateEntry>? cultivateEntries;
|
||||
private List<StatisticsCultivateItem>? statisticsItems;
|
||||
private ObservableCollection<StatisticsCultivateItem>? statisticsItems;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的养成视图模型
|
||||
@@ -53,8 +55,8 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
RemoveProjectCommand = new AsyncRelayCommand<CultivateProject>(RemoveProjectAsync);
|
||||
RemoveEntryCommand = new AsyncRelayCommand<Model.Binding.Cultivation.CultivateEntry>(RemoveEntryAsync);
|
||||
SaveInventoryItemCommand = new RelayCommand<Model.Binding.Inventory.InventoryItem>(SaveInventoryItem);
|
||||
UpdateStatisticsItemsCommand = new AsyncRelayCommand(UpdateStatisticsItemsAsync);
|
||||
NavigateToPageCommand = new RelayCommand<string>(NavigateToPage);
|
||||
FinishStateCommand = new RelayCommand<Model.Binding.Cultivation.CultivateItem>(FlipFinishedState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,7 +76,7 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
cultivationService.Current = value;
|
||||
if (value != null)
|
||||
{
|
||||
UpdateCultivateEntriesAndInventoryItemsAsync(value).SafeForget(logger);
|
||||
UpdateEntryCollectionAsync(value).SafeForget(logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +95,7 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
/// <summary>
|
||||
/// 统计列表
|
||||
/// </summary>
|
||||
public List<StatisticsCultivateItem>? StatisticsItems { get => statisticsItems; set => SetProperty(ref statisticsItems, value); }
|
||||
public ObservableCollection<StatisticsCultivateItem>? StatisticsItems { get => statisticsItems; set => SetProperty(ref statisticsItems, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 打开界面命令
|
||||
@@ -120,16 +122,16 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
public ICommand SaveInventoryItemCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 展示统计物品命令
|
||||
/// </summary>
|
||||
public ICommand UpdateStatisticsItemsCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航到指定的页面命令
|
||||
/// </summary>
|
||||
public ICommand NavigateToPageCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调整完成状态命令
|
||||
/// </summary>
|
||||
public ICommand FinishStateCommand { get; }
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
bool metaInitialized = await metadataService.InitializeAsync().ConfigureAwait(true);
|
||||
@@ -137,7 +139,6 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
{
|
||||
Projects = cultivationService.GetProjectCollection();
|
||||
SelectedProject = cultivationService.Current;
|
||||
await UpdateCultivateEntriesAndInventoryItemsAsync(SelectedProject).ConfigureAwait(true);
|
||||
}
|
||||
|
||||
IsInitialized = metaInitialized;
|
||||
@@ -184,7 +185,7 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateCultivateEntriesAndInventoryItemsAsync(CultivateProject? project)
|
||||
private async Task UpdateEntryCollectionAsync(CultivateProject? project)
|
||||
{
|
||||
if (project != null)
|
||||
{
|
||||
@@ -193,24 +194,25 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
Dictionary<Model.Primitive.WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
|
||||
|
||||
ObservableCollection<Model.Binding.Cultivation.CultivateEntry> entries = await cultivationService
|
||||
.GetCultivateEntriesAsync(project, materials, idAvatarMap, idWeaponMap)
|
||||
.GetCultivateEntriesAsync(project)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
CultivateEntries = entries;
|
||||
InventoryItems = cultivationService.GetInventoryItems(project, materials);
|
||||
|
||||
await UpdateStatisticsItemsAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private Task RemoveEntryAsync(Model.Binding.Cultivation.CultivateEntry? entry)
|
||||
private async Task RemoveEntryAsync(Model.Binding.Cultivation.CultivateEntry? entry)
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
CultivateEntries!.Remove(entry);
|
||||
return cultivationService.RemoveCultivateEntryAsync(entry.EntryId);
|
||||
await cultivationService.RemoveCultivateEntryAsync(entry.EntryId).ConfigureAwait(false);
|
||||
await UpdateStatisticsItemsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void SaveInventoryItem(Model.Binding.Inventory.InventoryItem? inventoryItem)
|
||||
@@ -218,20 +220,39 @@ internal class CultivationViewModel : Abstraction.ViewModel
|
||||
if (inventoryItem != null)
|
||||
{
|
||||
cultivationService.SaveInventoryItem(inventoryItem);
|
||||
UpdateStatisticsItemsAsync().SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
private void FlipFinishedState(Model.Binding.Cultivation.CultivateItem? item)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.IsFinished = !item.IsFinished;
|
||||
cultivationService.SaveCultivateItem(item.Entity);
|
||||
UpdateStatisticsItemsAsync().SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateStatisticsItemsAsync()
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(true))
|
||||
logger.LogInformation("UpdateStatisticsItemsAsync");
|
||||
if (SelectedProject != null)
|
||||
{
|
||||
if (SelectedProject != null)
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
CancellationToken token = statisticsCancellationTokenSource.Register();
|
||||
ObservableCollection<StatisticsCultivateItem> statistics;
|
||||
try
|
||||
{
|
||||
List<Model.Metadata.Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
|
||||
List<StatisticsCultivateItem> temp = await cultivationService.GetStatisticsCultivateItemsAsync(SelectedProject, materials).ConfigureAwait(false);
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
StatisticsItems = temp;
|
||||
statistics = await cultivationService.GetStatisticsCultivateItemCollectionAsync(SelectedProject, token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
StatisticsItems = statistics;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ internal class GachaLogViewModel : Abstraction.ViewModel
|
||||
public GachaArchive? SelectedArchive
|
||||
{
|
||||
get => selectedArchive;
|
||||
set => SetSelectedArchiveAndUpdateStatistics(value, false);
|
||||
set => SetSelectedArchiveAndUpdateStatistics(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,7 +158,6 @@ internal class GachaLogViewModel : Abstraction.ViewModel
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
Archives = archives;
|
||||
SelectedArchive = Archives.SingleOrDefault(a => a.IsSelected == true);
|
||||
IsInitialized = true;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -323,9 +322,14 @@ internal class GachaLogViewModel : Abstraction.ViewModel
|
||||
OnPropertyChanged(nameof(SelectedArchive));
|
||||
}
|
||||
|
||||
if (changed || forceUpdate)
|
||||
if (forceUpdate || changed)
|
||||
{
|
||||
if (archive != null)
|
||||
if (archive == null)
|
||||
{
|
||||
// no gachalog
|
||||
IsInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateStatisticsAsync(archive).SafeForget();
|
||||
}
|
||||
@@ -337,6 +341,7 @@ internal class GachaLogViewModel : Abstraction.ViewModel
|
||||
GachaStatistics temp = await gachaLogService.GetStatisticsAsync(archive).ConfigureAwait(false);
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
Statistics = temp;
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
private async Task<bool> TryImportUIGFInternalAsync(UIGF uigf)
|
||||
|
||||
@@ -230,9 +230,18 @@ public class MiHoYoJSInterface
|
||||
/// </summary>
|
||||
/// <param name="param">参数</param>
|
||||
/// <returns>响应</returns>
|
||||
public virtual IJsResult? ClosePage(JsParam param)
|
||||
public virtual async Task<IJsResult?> ClosePageAsync(JsParam param)
|
||||
{
|
||||
ClosePageRequested?.Invoke();
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
if (webView.CanGoBack)
|
||||
{
|
||||
webView.GoBack();
|
||||
}
|
||||
else
|
||||
{
|
||||
ClosePageRequested?.Invoke();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -357,7 +366,7 @@ public class MiHoYoJSInterface
|
||||
{
|
||||
return param.Method switch
|
||||
{
|
||||
"closePage" => ClosePage(param),
|
||||
"closePage" => await ClosePageAsync(param).ConfigureAwait(false),
|
||||
"configure_share" => ConfigureShare(param),
|
||||
"eventTrack" => null,
|
||||
"getActionTicket" => await GetActionTicketAsync(param).ConfigureAwait(false),
|
||||
|
||||
Reference in New Issue
Block a user