mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
spiral abyss rework
This commit is contained in:
@@ -89,6 +89,12 @@ internal sealed class IdentityGenerator : IIncrementalGenerator
|
|||||||
{
|
{
|
||||||
return Value.GetHashCode();
|
return Value.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
x:Class="Snap.Hutao.App"
|
x:Class="Snap.Hutao.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
|
|
||||||
xmlns:cwc="using:CommunityToolkit.WinUI.Converters"
|
xmlns:cwc="using:CommunityToolkit.WinUI.Converters"
|
||||||
|
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Control;
|
|||||||
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
|
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
|
||||||
internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
|
internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
|
||||||
{
|
{
|
||||||
private static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(Loading), new PropertyMetadata(default(bool), IsLoadingPropertyChanged));
|
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(Loading), new PropertyMetadata(default(bool), IsLoadingPropertyChanged));
|
||||||
|
|
||||||
private FrameworkElement? presenter;
|
private FrameworkElement? presenter;
|
||||||
|
|
||||||
|
|||||||
@@ -11,20 +11,6 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static partial class EnumerableExtension
|
internal static partial class EnumerableExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 尝试添加物品
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">物品类型</typeparam>
|
|
||||||
/// <param name="collection">集合</param>
|
|
||||||
/// <param name="item">物品</param>
|
|
||||||
public static void AddIfNotContains<T>(this Collection<T> collection, T item)
|
|
||||||
{
|
|
||||||
if (!collection.Contains(item))
|
|
||||||
{
|
|
||||||
collection.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this Collection<TSource>? source)
|
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this Collection<TSource>? source)
|
||||||
{
|
{
|
||||||
@@ -57,4 +43,17 @@ internal static partial class EnumerableExtension
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int FirstIndexOf<T>(this Collection<T> collection, Func<T, bool> predicate)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < collection.Count; index++)
|
||||||
|
{
|
||||||
|
if (predicate(collection[index]))
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,14 +59,4 @@ internal sealed class SpiralAbyssEntry : ObservableObject,
|
|||||||
SpiralAbyss = spiralAbyss,
|
SpiralAbyss = spiralAbyss,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新深渊信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="spiralAbyss">深渊信息</param>
|
|
||||||
public void UpdateSpiralAbyss(Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss spiralAbyss)
|
|
||||||
{
|
|
||||||
SpiralAbyss = spiralAbyss;
|
|
||||||
OnPropertyChanged(nameof(SpiralAbyss));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -862,7 +862,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 打怪 的本地化字符串。
|
/// 查找类似 击败怪物 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ModelMetadataTowerGoalTypeDefeatMonsters {
|
internal static string ModelMetadataTowerGoalTypeDefeatMonsters {
|
||||||
get {
|
get {
|
||||||
@@ -871,7 +871,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 守塔 的本地化字符串。
|
/// 查找类似 守护目标 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ModelMetadataTowerGoalTypeDefendTarget {
|
internal static string ModelMetadataTowerGoalTypeDefendTarget {
|
||||||
get {
|
get {
|
||||||
@@ -880,7 +880,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 附加 的本地化字符串。
|
/// 查找类似 附加:增援怪物 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ModelMetadataTowerWaveTypeAdditional {
|
internal static string ModelMetadataTowerWaveTypeAdditional {
|
||||||
get {
|
get {
|
||||||
@@ -1060,7 +1060,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 第一波附加:为第一波补充怪物 的本地化字符串。
|
/// 查找类似 第一波附加:增援第一波怪物 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ModelMetadataTowerWaveTypeWave1Additional {
|
internal static string ModelMetadataTowerWaveTypeWave1Additional {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -414,13 +414,13 @@
|
|||||||
<comment>Need EXACT same string in game</comment>
|
<comment>Need EXACT same string in game</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
|
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
|
||||||
<value>打怪</value>
|
<value>击败怪物</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
|
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
|
||||||
<value>守塔</value>
|
<value>守护目标</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
|
||||||
<value>附加</value>
|
<value>附加:增援怪物</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
|
||||||
<value>A组:不同的组同时在场,各自分波独立</value>
|
<value>A组:不同的组同时在场,各自分波独立</value>
|
||||||
@@ -480,7 +480,7 @@
|
|||||||
<value>第一波:击败所有怪物,下一波才会出现</value>
|
<value>第一波:击败所有怪物,下一波才会出现</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
|
||||||
<value>第一波附加:为第一波补充怪物</value>
|
<value>第一波附加:增援第一波怪物</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
|
||||||
<value>第二波:击败所有怪物,下一波才会出现</value>
|
<value>第二波:击败所有怪物,下一波才会出现</value>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Item;
|
using Snap.Hutao.Model.Metadata.Item;
|
||||||
|
using Snap.Hutao.Model.Metadata.Monster;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
using Snap.Hutao.Model.Metadata.Tower;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
@@ -70,10 +72,18 @@ internal interface IMetadataServiceIdDataMap
|
|||||||
/// <returns>字典</returns>
|
/// <returns>字典</returns>
|
||||||
ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
ValueTask<Dictionary<TowerScheduleId, TowerSchedule>> GetIdToTowerScheduleMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取ID到武器的字典
|
/// 异步获取ID到武器的字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>Id到武器的字典</returns>
|
/// <returns>Id到武器的字典</returns>
|
||||||
ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
ValueTask<Dictionary<TowerLevelGroupId, List<TowerLevel>>> GetGroupIdToTowerLevelGroupMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
ValueTask<Dictionary<TowerFloorId, TowerFloor>> GetIdToTowerFloorMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
ValueTask<Dictionary<MonsterRelationshipId, Monster>> GetRelationshipIdToMonsterMapAsync(CancellationToken token = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Item;
|
using Snap.Hutao.Model.Metadata.Item;
|
||||||
|
using Snap.Hutao.Model.Metadata.Monster;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
using Snap.Hutao.Model.Metadata.Tower;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
@@ -41,6 +43,21 @@ internal sealed partial class MetadataService
|
|||||||
return memoryCache.Set(cacheKey, dict);
|
return memoryCache.Set(cacheKey, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ValueTask<Dictionary<TowerLevelGroupId, List<TowerLevel>>> GetGroupIdToTowerLevelGroupMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
string cacheKey = $"{nameof(MetadataService)}.Cache.{FileNameTowerLevel}.Map.Group.{nameof(TowerLevelGroupId)}";
|
||||||
|
|
||||||
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
|
return (Dictionary<TowerLevelGroupId, List<TowerLevel>>)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TowerLevel> list = await FromCacheOrFileAsync<List<TowerLevel>>(FileNameTowerLevel, token).ConfigureAwait(false);
|
||||||
|
Dictionary<TowerLevelGroupId, List<TowerLevel>> dict = list.GroupBy(l => l.GroupId).ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
return memoryCache.Set(cacheKey, dict);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@@ -102,6 +119,16 @@ internal sealed partial class MetadataService
|
|||||||
return FromCacheAsDictionaryAsync<ReliquaryMainAffixId, FightProperty, ReliquaryMainAffix>(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token);
|
return FromCacheAsDictionaryAsync<ReliquaryMainAffixId, FightProperty, ReliquaryMainAffix>(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueTask<Dictionary<TowerFloorId, TowerFloor>> GetIdToTowerFloorMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<TowerFloorId, TowerFloor>(FileNameTowerFloor, t => t.Id, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask<Dictionary<TowerScheduleId, TowerSchedule>> GetIdToTowerScheduleMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<TowerScheduleId, TowerSchedule>(FileNameTowerSchedule, t => t.Id, token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@@ -126,6 +153,11 @@ internal sealed partial class MetadataService
|
|||||||
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameWeaponCurve, w => w.Level, w => w.Map, token);
|
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameWeaponCurve, w => w.Level, w => w.Map, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueTask<Dictionary<MonsterRelationshipId, Monster>> GetRelationshipIdToMonsterMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<MonsterRelationshipId, Monster>(FileNameMonster, m => m.RelationshipId, token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ internal interface ISpiralAbyssRecordDbService
|
|||||||
{
|
{
|
||||||
ValueTask AddSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
|
ValueTask AddSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
|
||||||
|
|
||||||
ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssEntryCollectionByUidAsync(string uid);
|
ValueTask<List<SpiralAbyssEntry>> GetSpiralAbyssEntryListByUidAsync(string uid);
|
||||||
|
|
||||||
ValueTask UpdateSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
|
ValueTask UpdateSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.ViewModel.SpiralAbyss;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
@@ -18,7 +19,9 @@ internal interface ISpiralAbyssRecordService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userAndUid">当前角色</param>
|
/// <param name="userAndUid">当前角色</param>
|
||||||
/// <returns>深渊记录集合</returns>
|
/// <returns>深渊记录集合</returns>
|
||||||
ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssCollectionAsync(UserAndUid userAndUid);
|
ValueTask<ObservableCollection<SpiralAbyssView>> GetSpiralAbyssViewCollectionAsync(UserAndUid userAndUid);
|
||||||
|
|
||||||
|
ValueTask<bool> InitializeAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步刷新深渊记录
|
/// 异步刷新深渊记录
|
||||||
|
|||||||
@@ -15,19 +15,16 @@ internal sealed partial class SpiralAbyssRecordDbService : ISpiralAbyssRecordDbS
|
|||||||
{
|
{
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
public async ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssEntryCollectionByUidAsync(string uid)
|
public async ValueTask<List<SpiralAbyssEntry>> GetSpiralAbyssEntryListByUidAsync(string uid)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
return await appDbContext.SpiralAbysses
|
||||||
List<SpiralAbyssEntry> entries = await appDbContext.SpiralAbysses
|
|
||||||
.Where(s => s.Uid == uid)
|
.Where(s => s.Uid == uid)
|
||||||
.OrderByDescending(s => s.ScheduleId)
|
.OrderByDescending(s => s.ScheduleId)
|
||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return entries.ToObservableCollection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Abstraction;
|
using Snap.Hutao.Core.DependencyInjection.Abstraction;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.Service.Metadata;
|
||||||
|
using Snap.Hutao.ViewModel.SpiralAbyss;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
@@ -18,15 +22,35 @@ namespace Snap.Hutao.Service.SpiralAbyss;
|
|||||||
[Injection(InjectAs.Scoped, typeof(ISpiralAbyssRecordService))]
|
[Injection(InjectAs.Scoped, typeof(ISpiralAbyssRecordService))]
|
||||||
internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordService
|
internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordService
|
||||||
{
|
{
|
||||||
private readonly ITaskContext taskContext;
|
|
||||||
private readonly IOverseaSupportFactory<IGameRecordClient> gameRecordClientFactory;
|
private readonly IOverseaSupportFactory<IGameRecordClient> gameRecordClientFactory;
|
||||||
private readonly ISpiralAbyssRecordDbService spiralAbyssRecordDbService;
|
private readonly ISpiralAbyssRecordDbService spiralAbyssRecordDbService;
|
||||||
|
private readonly IMetadataService metadataService;
|
||||||
|
private readonly ITaskContext taskContext;
|
||||||
|
|
||||||
private string? uid;
|
private string? uid;
|
||||||
private ObservableCollection<SpiralAbyssEntry>? spiralAbysses;
|
private ObservableCollection<SpiralAbyssView>? spiralAbysses;
|
||||||
|
private SpiralAbyssMetadataContext? metadataContext;
|
||||||
|
|
||||||
|
public async ValueTask<bool> InitializeAsync()
|
||||||
|
{
|
||||||
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
metadataContext = new()
|
||||||
|
{
|
||||||
|
IdScheduleMap = await metadataService.GetIdToTowerScheduleMapAsync().ConfigureAwait(false),
|
||||||
|
IdFloorMap = await metadataService.GetIdToTowerFloorMapAsync().ConfigureAwait(false),
|
||||||
|
IdLevelGroupMap = await metadataService.GetGroupIdToTowerLevelGroupMapAsync().ConfigureAwait(false),
|
||||||
|
IdMonsterMap = await metadataService.GetRelationshipIdToMonsterMapAsync().ConfigureAwait(false),
|
||||||
|
IdAvatarMap = AvatarIds.WithPlayers(await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false)),
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssCollectionAsync(UserAndUid userAndUid)
|
public async ValueTask<ObservableCollection<SpiralAbyssView>> GetSpiralAbyssViewCollectionAsync(UserAndUid userAndUid)
|
||||||
{
|
{
|
||||||
if (uid != userAndUid.Uid.Value)
|
if (uid != userAndUid.Uid.Value)
|
||||||
{
|
{
|
||||||
@@ -34,16 +58,27 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
uid = userAndUid.Uid.Value;
|
uid = userAndUid.Uid.Value;
|
||||||
spiralAbysses ??= await spiralAbyssRecordDbService
|
if (spiralAbysses is null)
|
||||||
.GetSpiralAbyssEntryCollectionByUidAsync(userAndUid.Uid.Value)
|
{
|
||||||
|
List<SpiralAbyssEntry> list = await spiralAbyssRecordDbService
|
||||||
|
.GetSpiralAbyssEntryListByUidAsync(userAndUid.Uid.Value)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(metadataContext);
|
||||||
|
spiralAbysses = list.SelectList(entity => SpiralAbyssView.From(entity, metadataContext)).ToObservableCollection();
|
||||||
|
}
|
||||||
|
|
||||||
return spiralAbysses;
|
return spiralAbysses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask RefreshSpiralAbyssAsync(UserAndUid userAndUid)
|
public async ValueTask RefreshSpiralAbyssAsync(UserAndUid userAndUid)
|
||||||
{
|
{
|
||||||
|
// request the index first
|
||||||
|
await gameRecordClientFactory
|
||||||
|
.Create(userAndUid.User.IsOversea)
|
||||||
|
.GetPlayerInfoAsync(userAndUid)
|
||||||
|
.ConfigureAwait(false);
|
||||||
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Last).ConfigureAwait(false);
|
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Last).ConfigureAwait(false);
|
||||||
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Current).ConfigureAwait(false);
|
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Current).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -60,20 +95,26 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi
|
|||||||
Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss webSpiralAbyss = response.Data;
|
Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss webSpiralAbyss = response.Data;
|
||||||
|
|
||||||
ArgumentNullException.ThrowIfNull(spiralAbysses);
|
ArgumentNullException.ThrowIfNull(spiralAbysses);
|
||||||
if (spiralAbysses.SingleOrDefault(s => s.ScheduleId == webSpiralAbyss.ScheduleId) is { } existEntry)
|
ArgumentNullException.ThrowIfNull(metadataContext);
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
existEntry.UpdateSpiralAbyss(webSpiralAbyss);
|
|
||||||
|
|
||||||
|
int index = spiralAbysses.FirstIndexOf(s => s.Entity.ScheduleId == webSpiralAbyss.ScheduleId);
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
await spiralAbyssRecordDbService.UpdateSpiralAbyssEntryAsync(existEntry).ConfigureAwait(false);
|
SpiralAbyssView view = spiralAbysses[index];
|
||||||
|
view.Entity.SpiralAbyss = webSpiralAbyss;
|
||||||
|
await spiralAbyssRecordDbService.UpdateSpiralAbyssEntryAsync(view.Entity).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
spiralAbysses.RemoveAt(index);
|
||||||
|
spiralAbysses.Insert(index, SpiralAbyssView.From(view.Entity, metadataContext));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SpiralAbyssEntry newEntry = SpiralAbyssEntry.From(userAndUid.Uid.Value, webSpiralAbyss);
|
SpiralAbyssEntry newEntry = SpiralAbyssEntry.From(userAndUid.Uid.Value, webSpiralAbyss);
|
||||||
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
spiralAbysses.Insert(0, newEntry);
|
spiralAbysses.Insert(0, SpiralAbyssView.From(newEntry, metadataContext));
|
||||||
|
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
await spiralAbyssRecordDbService.AddSpiralAbyssEntryAsync(newEntry).ConfigureAwait(false);
|
await spiralAbyssRecordDbService.AddSpiralAbyssEntryAsync(newEntry).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -188,12 +188,17 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</ListView.ItemContainerStyle>
|
</ListView.ItemContainerStyle>
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate x:DataType="shva:AchievementView">
|
||||||
<Border
|
<Border
|
||||||
Margin="0,4,0,0"
|
Margin="0,4,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource BorderCardStyle}">
|
Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Border.ContextFlyout>
|
||||||
|
<MenuFlyout>
|
||||||
|
<MenuFlyoutItem IsEnabled="False" Text="{Binding Inner.Id}"/>
|
||||||
|
</MenuFlyout>
|
||||||
|
</Border.ContextFlyout>
|
||||||
<Grid MinHeight="48" Padding="8">
|
<Grid MinHeight="48" Padding="8">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
|||||||
@@ -27,15 +27,15 @@
|
|||||||
IsPaneOpen="True"
|
IsPaneOpen="True"
|
||||||
OpenPaneLength="120"
|
OpenPaneLength="120"
|
||||||
PaneBackground="Transparent"
|
PaneBackground="Transparent"
|
||||||
Visibility="{Binding SpiralAbyssView, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
Visibility="{Binding SelectedView, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||||
<SplitView.Pane>
|
<SplitView.Pane>
|
||||||
<ListView
|
<ListView
|
||||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
ItemsSource="{Binding SpiralAbyssEntries}"
|
ItemsSource="{Binding SpiralAbyssEntries}"
|
||||||
SelectedItem="{Binding SelectedEntry, Mode=TwoWay}">
|
SelectedItem="{Binding SelectedView, Mode=TwoWay}">
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Schedule}"/>
|
<TextBlock Text="{Binding Entity.Schedule}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
</ListView>
|
</ListView>
|
||||||
@@ -55,30 +55,32 @@
|
|||||||
Label="{shcm:ResourceString Name=ViewSpiralAbyssRefresh}"/>
|
Label="{shcm:ResourceString Name=ViewSpiralAbyssRefresh}"/>
|
||||||
</CommandBar>
|
</CommandBar>
|
||||||
</Pivot.RightHeader>
|
</Pivot.RightHeader>
|
||||||
<PivotItem DataContext="{Binding SpiralAbyssView}" Header="{shcm:ResourceString Name=ViewSpiralAbyssStatistics}">
|
<PivotItem DataContext="{Binding SelectedView}" Header="{shcm:ResourceString Name=ViewSpiralAbyssStatistics}">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<Grid>
|
<Grid>
|
||||||
|
<Grid.Resources>
|
||||||
|
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
||||||
|
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
|
||||||
|
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
|
||||||
|
</Grid.Resources>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition MaxWidth="600"/>
|
<ColumnDefinition Width="286"/>
|
||||||
|
<ColumnDefinition Width="286"/>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="16,0,8,16"
|
Margin="16,0,8,16"
|
||||||
Spacing="{StaticResource SettingsCardSpacing}">
|
Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
<StackPanel.Resources>
|
|
||||||
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
|
||||||
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
|
|
||||||
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
|
|
||||||
</StackPanel.Resources>
|
|
||||||
<cwc:SettingsCard
|
|
||||||
Margin="0,16,0,0"
|
|
||||||
Content="{Binding TotalBattleTimes}"
|
|
||||||
Header="{shcm:ResourceString Name=ViewSpiralAbyssBattleTimes}"/>
|
|
||||||
<cwc:SettingsCard Content="{Binding TotalStar}" Header="{shcm:ResourceString Name=ViewSpiralAbyssTotalStar}"/>
|
|
||||||
<cwc:SettingsCard Content="{Binding MaxFloor}" Header="{shcm:ResourceString Name=ViewSpiralAbyssMaxFloor}"/>
|
<cwc:SettingsCard Content="{Binding MaxFloor}" Header="{shcm:ResourceString Name=ViewSpiralAbyssMaxFloor}"/>
|
||||||
|
<cwc:SettingsCard Content="{Binding TotalBattleTimes}" Header="{shcm:ResourceString Name=ViewSpiralAbyssBattleTimes}"/>
|
||||||
|
<cwc:SettingsCard Content="{Binding TotalStar}" Header="{shcm:ResourceString Name=ViewSpiralAbyssTotalStar}"/>
|
||||||
|
|
||||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewSpiralAbyssReveal}"/>
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="1,6,0,5"
|
||||||
|
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewSpiralAbyssReveal}"/>
|
||||||
<ItemsControl HorizontalAlignment="Left" ItemsSource="{Binding Reveals}">
|
<ItemsControl HorizontalAlignment="Left" ItemsSource="{Binding Reveals}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
@@ -88,13 +90,19 @@
|
|||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<shvc:BottomTextControl Text="{Binding Value}">
|
<shvc:BottomTextControl Text="{Binding Value}">
|
||||||
<shvc:ItemIcon Icon="{Binding Icon}" Quality="{Binding Quality}"/>
|
<shvc:ItemIcon
|
||||||
|
Width="52"
|
||||||
|
Height="52"
|
||||||
|
Icon="{Binding Icon}"
|
||||||
|
Quality="{Binding Quality}"/>
|
||||||
</shvc:BottomTextControl>
|
</shvc:BottomTextControl>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewSpiralAbyssBattleHeader}"/>
|
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewSpiralAbyssDefeat}">
|
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewSpiralAbyssDefeat}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -166,10 +174,9 @@
|
|||||||
</cwc:SettingsCard>
|
</cwc:SettingsCard>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem DataContext="{Binding SpiralAbyssView}" Header="{shcm:ResourceString Name=ViewSpiralAbyssDetail}">
|
<PivotItem DataContext="{Binding SelectedView}" Header="{shcm:ResourceString Name=ViewSpiralAbyssDetail}">
|
||||||
<ScrollViewer VerticalAlignment="Top" HorizontalScrollBarVisibility="Auto">
|
<ScrollViewer VerticalAlignment="Top" HorizontalScrollBarVisibility="Auto">
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
Margin="16,16,0,0"
|
Margin="16,16,0,0"
|
||||||
@@ -289,7 +296,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</SplitView.Content>
|
</SplitView.Content>
|
||||||
</SplitView>
|
</SplitView>
|
||||||
<Grid Visibility="{Binding SpiralAbyssView, Converter={StaticResource EmptyObjectToVisibilityRevertConverter}}">
|
<Grid Visibility="{Binding SelectedView, Converter={StaticResource EmptyObjectToVisibilityRevertConverter}}">
|
||||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
<shci:CachedImage
|
<shci:CachedImage
|
||||||
Width="120"
|
Width="120"
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
using Snap.Hutao.Model.Metadata.Monster;
|
||||||
|
using Snap.Hutao.Model.Metadata.Tower;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.ViewModel.SpiralAbyss;
|
||||||
|
|
||||||
|
internal sealed class SpiralAbyssMetadataContext
|
||||||
|
{
|
||||||
|
public Dictionary<TowerScheduleId, TowerSchedule> IdScheduleMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<TowerFloorId, TowerFloor> IdFloorMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<TowerLevelGroupId, List<TowerLevel>> IdLevelGroupMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<MonsterRelationshipId, Monster> IdMonsterMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -27,42 +27,22 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
|||||||
{
|
{
|
||||||
private readonly ISpiralAbyssRecordService spiralAbyssRecordService;
|
private readonly ISpiralAbyssRecordService spiralAbyssRecordService;
|
||||||
private readonly HomaSpiralAbyssClient spiralAbyssClient;
|
private readonly HomaSpiralAbyssClient spiralAbyssClient;
|
||||||
private readonly IMetadataService metadataService;
|
|
||||||
private readonly IInfoBarService infoBarService;
|
private readonly IInfoBarService infoBarService;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly IUserService userService;
|
private readonly IUserService userService;
|
||||||
|
|
||||||
private Dictionary<AvatarId, Model.Metadata.Avatar.Avatar>? idAvatarMap;
|
private ObservableCollection<SpiralAbyssView>? spiralAbyssEntries;
|
||||||
private ObservableCollection<SpiralAbyssEntry>? spiralAbyssEntries;
|
private SpiralAbyssView? selectedView;
|
||||||
private SpiralAbyssEntry? selectedEntry;
|
|
||||||
private SpiralAbyssView? spiralAbyssView;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 深渊记录
|
/// 深渊记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ObservableCollection<SpiralAbyssEntry>? SpiralAbyssEntries { get => spiralAbyssEntries; set => SetProperty(ref spiralAbyssEntries, value); }
|
public ObservableCollection<SpiralAbyssView>? SpiralAbyssEntries { get => spiralAbyssEntries; set => SetProperty(ref spiralAbyssEntries, value); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选中的深渊信息
|
/// 选中的深渊信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SpiralAbyssEntry? SelectedEntry
|
public SpiralAbyssView? SelectedView { get => selectedView; set => SetProperty(ref selectedView, value); }
|
||||||
{
|
|
||||||
get => selectedEntry; set
|
|
||||||
{
|
|
||||||
// We dont need to check the result here,
|
|
||||||
// just refresh the view anyway.
|
|
||||||
SetProperty(ref selectedEntry, value);
|
|
||||||
if (value is not null && idAvatarMap is not null)
|
|
||||||
{
|
|
||||||
SpiralAbyssView = new(value.SpiralAbyss, idAvatarMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 深渊的只读视图
|
|
||||||
/// </summary>
|
|
||||||
public SpiralAbyssView? SpiralAbyssView { get => spiralAbyssView; set => SetProperty(ref spiralAbyssView, value); }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Receive(UserChangedMessage message)
|
public void Receive(UserChangedMessage message)
|
||||||
@@ -73,17 +53,14 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SpiralAbyssView = null;
|
SelectedView = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask<bool> InitializeUIAsync()
|
protected override async ValueTask<bool> InitializeUIAsync()
|
||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await spiralAbyssRecordService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
|
|
||||||
idAvatarMap = AvatarIds.WithPlayers(idAvatarMap);
|
|
||||||
|
|
||||||
if (UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid))
|
if (UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid))
|
||||||
{
|
{
|
||||||
await UpdateSpiralAbyssCollectionAsync(userAndUid).ConfigureAwait(false);
|
await UpdateSpiralAbyssCollectionAsync(userAndUid).ConfigureAwait(false);
|
||||||
@@ -100,13 +77,13 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
private async ValueTask UpdateSpiralAbyssCollectionAsync(UserAndUid userAndUid)
|
private async ValueTask UpdateSpiralAbyssCollectionAsync(UserAndUid userAndUid)
|
||||||
{
|
{
|
||||||
ObservableCollection<SpiralAbyssEntry>? temp = null;
|
ObservableCollection<SpiralAbyssView>? collection = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
temp = await spiralAbyssRecordService
|
collection = await spiralAbyssRecordService
|
||||||
.GetSpiralAbyssCollectionAsync(userAndUid)
|
.GetSpiralAbyssViewCollectionAsync(userAndUid)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,8 +92,8 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
SpiralAbyssEntries = temp;
|
SpiralAbyssEntries = collection;
|
||||||
SelectedEntry = SpiralAbyssEntries?.FirstOrDefault();
|
SelectedView = SpiralAbyssEntries?.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("RefreshCommand")]
|
[Command("RefreshCommand")]
|
||||||
@@ -140,7 +117,7 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
SelectedEntry = SpiralAbyssEntries.FirstOrDefault();
|
SelectedView = SpiralAbyssEntries.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Abstraction;
|
||||||
|
using Snap.Hutao.Model;
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
using Snap.Hutao.Model.Metadata.Tower;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.SpiralAbyss;
|
namespace Snap.Hutao.ViewModel.SpiralAbyss;
|
||||||
@@ -9,27 +14,47 @@ namespace Snap.Hutao.ViewModel.SpiralAbyss;
|
|||||||
/// 深渊视图
|
/// 深渊视图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class SpiralAbyssView
|
internal sealed class SpiralAbyssView : IEntityOnly<SpiralAbyssEntry>,
|
||||||
|
IMappingFrom<SpiralAbyssView, SpiralAbyssEntry, SpiralAbyssMetadataContext>
|
||||||
{
|
{
|
||||||
|
private readonly SpiralAbyssEntry entity;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的深渊视图
|
/// 构造一个新的深渊视图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="spiralAbyss">深渊信息</param>
|
/// <param name="entity">实体</param>
|
||||||
/// <param name="idAvatarMap">Id角色映射</param>
|
/// <param name="idAvatarMap">Id角色映射</param>
|
||||||
public SpiralAbyssView(Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss spiralAbyss, Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap)
|
private SpiralAbyssView(SpiralAbyssEntry entity, SpiralAbyssMetadataContext context)
|
||||||
{
|
{
|
||||||
|
this.entity = entity;
|
||||||
|
Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss spiralAbyss = entity.SpiralAbyss;
|
||||||
|
|
||||||
|
TowerSchedule towerSchedule = context.IdScheduleMap[(uint)entity.ScheduleId];
|
||||||
|
TimeFormatted = $"{towerSchedule.Open:yyyy/MM/dd HH:mm:ss} - {towerSchedule.Close:yyyy/MM/dd HH:mm:ss}";
|
||||||
|
|
||||||
|
BlessingName = towerSchedule.BuffName;
|
||||||
|
Blessings = towerSchedule.Descriptions;
|
||||||
|
|
||||||
TotalBattleTimes = spiralAbyss.TotalBattleTimes;
|
TotalBattleTimes = spiralAbyss.TotalBattleTimes;
|
||||||
TotalStar = spiralAbyss.TotalStar;
|
TotalStar = spiralAbyss.TotalStar;
|
||||||
MaxFloor = spiralAbyss.MaxFloor;
|
MaxFloor = spiralAbyss.MaxFloor;
|
||||||
Reveals = spiralAbyss.RevealRank.SelectList(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId]));
|
Reveals = spiralAbyss.RevealRank.SelectList(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId]));
|
||||||
Defeat = spiralAbyss.DefeatRank.Select(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId])).SingleOrDefault();
|
Defeat = spiralAbyss.DefeatRank.Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault();
|
||||||
Damage = spiralAbyss.DamageRank.Select(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId])).SingleOrDefault();
|
Damage = spiralAbyss.DamageRank.Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault();
|
||||||
TakeDamage = spiralAbyss.TakeDamageRank.Select(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId])).SingleOrDefault();
|
TakeDamage = spiralAbyss.TakeDamageRank.Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault();
|
||||||
NormalSkill = spiralAbyss.NormalSkillRank.Select(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId])).SingleOrDefault();
|
NormalSkill = spiralAbyss.NormalSkillRank.Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault();
|
||||||
EnergySkill = spiralAbyss.EnergySkillRank.Select(r => new RankAvatar(r.Value, idAvatarMap[r.AvatarId])).SingleOrDefault();
|
EnergySkill = spiralAbyss.EnergySkillRank.Select(r => new RankAvatar(r.Value, context.IdAvatarMap[r.AvatarId])).SingleOrDefault();
|
||||||
Floors = spiralAbyss.Floors.Select(f => new FloorView(f, idAvatarMap)).Reverse().ToList();
|
Floors = spiralAbyss.Floors.Select(f => new FloorView(f, context.IdAvatarMap)).Reverse().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpiralAbyssEntry Entity { get => entity; }
|
||||||
|
|
||||||
|
public string TimeFormatted { get; }
|
||||||
|
|
||||||
|
public string BlessingName { get; }
|
||||||
|
|
||||||
|
public List<string> Blessings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 战斗次数
|
/// 战斗次数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -79,4 +104,9 @@ internal sealed class SpiralAbyssView
|
|||||||
/// 层信息
|
/// 层信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<FloorView> Floors { get; }
|
public List<FloorView> Floors { get; }
|
||||||
|
|
||||||
|
public static SpiralAbyssView From(SpiralAbyssEntry entity, SpiralAbyssMetadataContext context)
|
||||||
|
{
|
||||||
|
return new(entity, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user