mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
achievement card
This commit is contained in:
@@ -46,6 +46,9 @@
|
||||
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
|
||||
<x:Double x:Key="CompatSplitViewOpenPaneLength2">268</x:Double>
|
||||
<GridLength x:Key="CompatGridLength2">268</GridLength>
|
||||
|
||||
<x:Double x:Key="HomeAdaptiveCardHeight">180</x:Double>
|
||||
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="AvatarPropertyAddValueBrush" Color="{ThemeResource AvatarPropertyAddValueColor}"/>
|
||||
<!-- Settings -->
|
||||
|
||||
@@ -21,10 +21,9 @@ internal static partial class EnumerableExtension
|
||||
}
|
||||
|
||||
long sum = 0;
|
||||
ref int reference = ref MemoryMarshal.GetReference(span);
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
foreach (int item in span)
|
||||
{
|
||||
sum += Unsafe.Add(ref reference, i);
|
||||
sum += item;
|
||||
}
|
||||
|
||||
return (double)sum / span.Length;
|
||||
@@ -78,11 +77,11 @@ internal static partial class EnumerableExtension
|
||||
public static List<TResult> SelectList<TSource, TResult>(this List<TSource> list, Func<TSource, TResult> selector)
|
||||
{
|
||||
Span<TSource> span = CollectionsMarshal.AsSpan(list);
|
||||
ref TSource reference = ref MemoryMarshal.GetReference(span);
|
||||
List<TResult> results = new(span.Length);
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
|
||||
foreach (TSource item in span)
|
||||
{
|
||||
results.Add(selector(Unsafe.Add(ref reference, i)));
|
||||
results.Add(selector(item));
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
@@ -1,47 +1,52 @@
|
||||
[
|
||||
[
|
||||
{
|
||||
"Name": "AvatarId",
|
||||
"Type": "int",
|
||||
"Documentation": "8λ <20><>ɫId"
|
||||
"Documentation": "8位 角色Id"
|
||||
},
|
||||
{
|
||||
"Name": "EquipAffixId",
|
||||
"Type": "int",
|
||||
"Documentation": "6λ װ<><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "6位 装备属性Id"
|
||||
},
|
||||
{
|
||||
"Name": "ExtendedEquipAffixId",
|
||||
"Type": "int",
|
||||
"Documentation": "7λ װ<><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "7位 装备属性Id"
|
||||
},
|
||||
{
|
||||
"Name": "MaterialId",
|
||||
"Type": "int",
|
||||
"Documentation": "3-6λ <20><><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "3-6位 材料Id"
|
||||
},
|
||||
{
|
||||
"Name": "MonsterId",
|
||||
"Type": "int",
|
||||
"Documentation": "8λ <20><><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "8位 怪物Id"
|
||||
},
|
||||
{
|
||||
"Name": "PromoteId",
|
||||
"Type": "int",
|
||||
"Documentation": "1-5λ <20><>ɫͻ<C9AB><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "1-5位 角色突破提升Id"
|
||||
},
|
||||
{
|
||||
"Name": "ReliquaryAffixId",
|
||||
"Type": "int",
|
||||
"Documentation": "6λ ʥ<><CAA5><EFBFBD>︱<EFBFBD><EFB8B1><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "6位 圣遗物副词条Id"
|
||||
},
|
||||
{
|
||||
"Name": "ReliquaryMainAffixId",
|
||||
"Type": "int",
|
||||
"Documentation": "5λ ʥ<><CAA5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "5位 圣遗物主属性Id"
|
||||
},
|
||||
{
|
||||
"Name": "WeaponId",
|
||||
"Type": "int",
|
||||
"Documentation": "5λ <20><><EFBFBD><EFBFBD>Id"
|
||||
"Documentation": "5位 武器Id"
|
||||
},
|
||||
{
|
||||
"Name": "AchievementId",
|
||||
"Type": "int",
|
||||
"Documentation": "5位 成就Id"
|
||||
}
|
||||
]
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
@@ -51,7 +52,7 @@ internal sealed class Achievement : IEquatable<Achievement>
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public AchievementInfoStatus Status { get; set; }
|
||||
public AchievementStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的成就
|
||||
@@ -59,7 +60,7 @@ internal sealed class Achievement : IEquatable<Achievement>
|
||||
/// <param name="userId">对应的用户id</param>
|
||||
/// <param name="id">成就Id</param>
|
||||
/// <returns>新创建的成就</returns>
|
||||
public static Achievement Create(in Guid userId, int id)
|
||||
public static Achievement Create(in Guid userId, in AchievementId id)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
@@ -83,7 +84,7 @@ internal sealed class Achievement : IEquatable<Achievement>
|
||||
ArchiveId = userId,
|
||||
Id = uiaf.Id,
|
||||
Current = uiaf.Current,
|
||||
Status = uiaf.Status, // Hot fix | 1.0.30 | Status not set when create database entity
|
||||
Status = uiaf.Status,
|
||||
Time = DateTimeOffset.FromUnixTimeSeconds(uiaf.Timestamp).ToLocalTime(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,5 +33,5 @@ internal sealed class UIAFItem
|
||||
/// 完成状态
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
public AchievementInfoStatus Status { get; set; }
|
||||
public AchievementStatus Status { get; set; }
|
||||
}
|
||||
@@ -7,12 +7,12 @@ namespace Snap.Hutao.Model.Intrinsic;
|
||||
/// 成就信息状态
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal enum AchievementInfoStatus
|
||||
internal enum AchievementStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 未识别
|
||||
/// </summary>
|
||||
UNRECOGNIZED = -1,
|
||||
STATUS_UNRECOGNIZED = -1,
|
||||
|
||||
/// <summary>
|
||||
/// 非法值
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
@@ -12,7 +14,7 @@ internal sealed class Achievement
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
public AchievementId Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分类Id
|
||||
|
||||
@@ -51,13 +51,10 @@ internal sealed partial class ParameterDescriptor : ValueConverter<DescriptionsP
|
||||
private static List<ParameterDescription> GetParameterInfos(List<DescFormat> formats, List<double> param)
|
||||
{
|
||||
Span<DescFormat> span = CollectionsMarshal.AsSpan(formats);
|
||||
ref DescFormat reference = ref MemoryMarshal.GetReference(span);
|
||||
|
||||
List<ParameterDescription> results = new(span.Length);
|
||||
for (int index = 0; index < span.Length; index++)
|
||||
{
|
||||
ref DescFormat descFormat = ref Unsafe.Add(ref reference, index);
|
||||
|
||||
foreach (DescFormat descFormat in span)
|
||||
{
|
||||
string format = descFormat.Format;
|
||||
string resultFormatted = ParamRegex().Replace(format, match => EvaluateMatch(match, param));
|
||||
results.Add(new ParameterDescription { Description = descFormat.Description, Parameter = resultFormatted });
|
||||
|
||||
@@ -1537,7 +1537,16 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 据上一个五/四星 的本地化字符串。
|
||||
/// 查找类似 成就统计 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewCardAchievementStatisticsTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewCardAchievementStatisticsTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 保底计数 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewCardGachaStatisticsTitle {
|
||||
get {
|
||||
|
||||
@@ -1963,6 +1963,9 @@
|
||||
<value>设置</value>
|
||||
</data>
|
||||
<data name="ViewCardGachaStatisticsTitle" xml:space="preserve">
|
||||
<value>据上一个五/四星</value>
|
||||
<value>保底计数</value>
|
||||
</data>
|
||||
<data name="ViewCardAchievementStatisticsTitle" xml:space="preserve">
|
||||
<value>成就统计</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,12 +6,13 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.Diagnostics;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.ViewModel.Achievement;
|
||||
using System.Collections.ObjectModel;
|
||||
using BindingAchievement = Snap.Hutao.ViewModel.Achievement.AchievementView;
|
||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
||||
|
||||
namespace Snap.Hutao.Service.Achievement;
|
||||
@@ -25,10 +26,10 @@ internal sealed class AchievementService : IAchievementService
|
||||
{
|
||||
private readonly AppDbContext appDbContext;
|
||||
private readonly ILogger<AchievementService> logger;
|
||||
private readonly DbCurrent<EntityArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
|
||||
private readonly DbCurrent<AchievementArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
|
||||
private readonly AchievementDbOperation achievementDbOperation;
|
||||
|
||||
private ObservableCollection<EntityArchive>? archiveCollection;
|
||||
private ObservableCollection<AchievementArchive>? archiveCollection;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的成就服务
|
||||
@@ -46,21 +47,21 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public EntityArchive? CurrentArchive
|
||||
public AchievementArchive? CurrentArchive
|
||||
{
|
||||
get => dbCurrent.Current;
|
||||
set => dbCurrent.Current = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ObservableCollection<EntityArchive>> GetArchiveCollectionAsync()
|
||||
public async Task<ObservableCollection<AchievementArchive>> GetArchiveCollectionAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
return archiveCollection ??= appDbContext.AchievementArchives.AsNoTracking().ToObservableCollection();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task RemoveArchiveAsync(EntityArchive archive)
|
||||
public async Task RemoveArchiveAsync(AchievementArchive archive)
|
||||
{
|
||||
// Sync cache
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
@@ -76,7 +77,7 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ArchiveAddResult> TryAddArchiveAsync(EntityArchive newArchive)
|
||||
public async Task<ArchiveAddResult> TryAddArchiveAsync(AchievementArchive newArchive)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newArchive.Name))
|
||||
{
|
||||
@@ -103,28 +104,25 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<BindingAchievement> GetAchievements(EntityArchive archive, IList<MetadataAchievement> metadata)
|
||||
public List<AchievementView> GetAchievements(AchievementArchive archive, List<MetadataAchievement> metadata)
|
||||
{
|
||||
Guid archiveId = archive.InnerId;
|
||||
List<EntityAchievement> entities = appDbContext.Achievements
|
||||
.Where(a => a.ArchiveId == archiveId)
|
||||
.ToList();
|
||||
Dictionary<int, EntityAchievement> entityMap;
|
||||
try
|
||||
{
|
||||
entityMap = appDbContext.Achievements
|
||||
.Where(a => a.ArchiveId == archive.InnerId)
|
||||
.AsEnumerable()
|
||||
.ToDictionary(a => a.Id);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
throw ThrowHelper.UserdataCorrupted(SH.ServiceAchievementUserdataCorruptedInnerIdNotUnique, ex);
|
||||
}
|
||||
|
||||
List<BindingAchievement> results = new();
|
||||
List<AchievementView> results = new();
|
||||
foreach (MetadataAchievement meta in metadata)
|
||||
{
|
||||
EntityAchievement? entity = null;
|
||||
try
|
||||
{
|
||||
entity = entities.SingleOrDefault(e => e.Id == meta.Id);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
ThrowHelper.UserdataCorrupted(SH.ServiceAchievementUserdataCorruptedInnerIdNotUnique, ex);
|
||||
}
|
||||
|
||||
entity ??= EntityAchievement.Create(archiveId, meta.Id);
|
||||
|
||||
EntityAchievement? entity = entityMap.GetValueOrDefault(meta.Id) ?? EntityAchievement.Create(archive.InnerId, meta.Id);
|
||||
results.Add(new(entity, meta));
|
||||
}
|
||||
|
||||
@@ -132,7 +130,40 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<UIAF> ExportToUIAFAsync(EntityArchive archive)
|
||||
public async Task<List<AchievementStatistics>> GetAchievementStatisticsAsync(Dictionary<AchievementId, MetadataAchievement> achievementMap)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
|
||||
List<AchievementStatistics> results = new();
|
||||
foreach (AchievementArchive archive in appDbContext.AchievementArchives)
|
||||
{
|
||||
int finished = await appDbContext.Achievements
|
||||
.Where(a => a.ArchiveId == archive.InnerId)
|
||||
.Where(a => (int)a.Status >= (int)Model.Intrinsic.AchievementStatus.STATUS_FINISHED)
|
||||
.CountAsync()
|
||||
.ConfigureAwait(false);
|
||||
int count = achievementMap.Count;
|
||||
|
||||
List<EntityAchievement> achievements = await appDbContext.Achievements
|
||||
.Where(a => a.ArchiveId == archive.InnerId)
|
||||
.OrderByDescending(a => a.Time.ToString())
|
||||
.Take(2)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
results.Add(new()
|
||||
{
|
||||
DisplayName = archive.Name,
|
||||
FinishDescription = $"{finished}/{count} - {(double)finished / count:P2}",
|
||||
Achievements = achievements.SelectList(entity => new AchievementView(entity, achievementMap[entity.Id])),
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<UIAF> ExportToUIAFAsync(AchievementArchive archive)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
List<UIAFItem> list = appDbContext.Achievements
|
||||
@@ -151,7 +182,7 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ImportResult> ImportFromUIAFAsync(EntityArchive archive, List<UIAFItem> list, ImportStrategy strategy)
|
||||
public async Task<ImportResult> ImportFromUIAFAsync(AchievementArchive archive, List<UIAFItem> list, ImportStrategy strategy)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
|
||||
@@ -185,7 +216,7 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveAchievements(EntityArchive archive, IList<BindingAchievement> achievements)
|
||||
public void SaveAchievements(AchievementArchive archive, List<AchievementView> achievements)
|
||||
{
|
||||
string name = archive.Name;
|
||||
logger.LogInformation("Begin saving achievements for [{name}]", name);
|
||||
@@ -203,7 +234,7 @@ internal sealed class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveAchievement(BindingAchievement achievement)
|
||||
public void SaveAchievement(AchievementView achievement)
|
||||
{
|
||||
// Delete exists one.
|
||||
appDbContext.Achievements.ExecuteDeleteWhere(e => e.InnerId == achievement.Entity.InnerId);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using System.Collections.ObjectModel;
|
||||
using BindingAchievement = Snap.Hutao.ViewModel.Achievement.AchievementView;
|
||||
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
@@ -33,7 +34,14 @@ internal interface IAchievementService
|
||||
/// <param name="archive">用户</param>
|
||||
/// <param name="metadata">元数据</param>
|
||||
/// <returns>整合的成就</returns>
|
||||
List<BindingAchievement> GetAchievements(EntityArchive archive, IList<MetadataAchievement> metadata);
|
||||
List<BindingAchievement> GetAchievements(EntityArchive archive, List<MetadataAchievement> metadata);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取成就统计列表
|
||||
/// </summary>
|
||||
/// <param name="achievementMap">成就映射</param>
|
||||
/// <returns>成就统计列表</returns>
|
||||
Task<List<ViewModel.Achievement.AchievementStatistics>> GetAchievementStatisticsAsync(Dictionary<AchievementId, MetadataAchievement> achievementMap);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取用于绑定的成就存档集合
|
||||
@@ -68,7 +76,7 @@ internal interface IAchievementService
|
||||
/// </summary>
|
||||
/// <param name="archive">用户</param>
|
||||
/// <param name="achievements">成就</param>
|
||||
void SaveAchievements(EntityArchive archive, IList<BindingAchievement> achievements);
|
||||
void SaveAchievements(EntityArchive archive, List<BindingAchievement> achievements);
|
||||
|
||||
/// <summary>
|
||||
/// 尝试添加存档
|
||||
|
||||
@@ -34,7 +34,7 @@ internal sealed class SummaryFactory : ISummaryFactory
|
||||
IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false),
|
||||
IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false),
|
||||
IdRelicMainPropMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false),
|
||||
IdReliquaryAffixMap = await metadataService.GetIdReliquaryAffixMapAsync(token).ConfigureAwait(false),
|
||||
IdReliquaryAffixMap = await metadataService.GetIdToReliquaryAffixMapAsync(token).ConfigureAwait(false),
|
||||
ReliqueryLevels = await metadataService.GetReliquaryLevelsAsync(token).ConfigureAwait(false),
|
||||
Reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false),
|
||||
};
|
||||
|
||||
@@ -60,6 +60,13 @@ internal interface IMetadataService : ICastableService
|
||||
/// <returns>卡池配置列表</returns>
|
||||
ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取成就映射
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>成就映射</returns>
|
||||
ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取Id到角色的字典
|
||||
/// </summary>
|
||||
@@ -67,6 +74,13 @@ internal interface IMetadataService : ICastableService
|
||||
/// <returns>Id到角色的字典</returns>
|
||||
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取显示与材料映射
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>显示与材料映射</returns>
|
||||
ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取Id到材料的字典
|
||||
/// </summary>
|
||||
@@ -79,7 +93,7 @@ internal interface IMetadataService : ICastableService
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>字典</returns>
|
||||
ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdReliquaryAffixMapAsync(CancellationToken token = default);
|
||||
ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdToReliquaryAffixMapAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取圣遗物主词条Id与属性的字典
|
||||
@@ -199,11 +213,4 @@ internal interface IMetadataService : ICastableService
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>武器突破列表</returns>
|
||||
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取显示与材料映射
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>显示与材料映射</returns>
|
||||
ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
@@ -22,6 +23,12 @@ internal sealed partial class MetadataService
|
||||
return FromCacheAsDictionaryAsync<EquipAffixId, ReliquarySet>("ReliquarySet", r => r.EquipAffixId, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
|
||||
{
|
||||
return FromCacheAsDictionaryAsync<AchievementId, Model.Metadata.Achievement.Achievement>("Achievement", a => a.Id, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default)
|
||||
{
|
||||
@@ -31,8 +38,15 @@ internal sealed partial class MetadataService
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default)
|
||||
{
|
||||
string cacheKey = $"{nameof(MetadataService)}.Cache.DisplayAndMaterial.Map.{typeof(MaterialId).Name}";
|
||||
|
||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||
{
|
||||
return Must.NotNull((Dictionary<MaterialId, Display>)value!);
|
||||
}
|
||||
|
||||
Dictionary<MaterialId, Display> displays = await FromCacheAsDictionaryAsync<MaterialId, Display>("Display", a => a.Id, token).ConfigureAwait(false);
|
||||
Dictionary<MaterialId, Material> materials = await FromCacheAsDictionaryAsync<MaterialId, Material>("Material", a => a.Id, token).ConfigureAwait(false);
|
||||
Dictionary<MaterialId, Material> materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
||||
|
||||
// TODO: Cache this
|
||||
Dictionary<MaterialId, Display> results = new(displays);
|
||||
@@ -42,7 +56,7 @@ internal sealed partial class MetadataService
|
||||
results[id] = material;
|
||||
}
|
||||
|
||||
return results;
|
||||
return memoryCache.Set(cacheKey, results);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -52,7 +66,7 @@ internal sealed partial class MetadataService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdReliquaryAffixMapAsync(CancellationToken token = default)
|
||||
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdToReliquaryAffixMapAsync(CancellationToken token = default)
|
||||
{
|
||||
return FromCacheAsDictionaryAsync<ReliquaryAffixId, ReliquaryAffix>("ReliquaryAffix", a => a.Id, token);
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
<!-- Packages -->
|
||||
<ItemGroup>
|
||||
<!-- https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json -->
|
||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.SettingsControls" Version="0.0.17" />
|
||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.SettingsControls" Version="0.0.18" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
||||
@@ -255,7 +255,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.206-beta">
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.221-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -3,9 +3,69 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Snap.Hutao.View.Card"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shva="using:Snap.Hutao.ViewModel.Achievement"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
d:DataContext="{d:DesignInstance shva:AchievementViewModelSlim}"
|
||||
Command="{Binding NavigateCommand}"
|
||||
Style="{ThemeResource DefaultButtonStyle}"
|
||||
mc:Ignorable="d">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<Grid>
|
||||
<FlipView
|
||||
Background="{x:Null}"
|
||||
ItemsSource="{Binding StatisticsList}"
|
||||
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<FlipView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Text="{shcm:ResourceString Name=ViewCardAchievementStatisticsTitle}"/>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Right"
|
||||
Text="{Binding DisplayName}"/>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,4,0,0"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="{Binding FinishDescription}"/>
|
||||
<ItemsControl Grid.Row="2" ItemsSource="{Binding Achievements}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="0,4,0,0">
|
||||
<TextBlock
|
||||
Opacity="0.8"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Inner.Title}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Time}"
|
||||
TextWrapping="NoWrap"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</FlipView.ItemTemplate>
|
||||
|
||||
<Grid/>
|
||||
</FlipView>
|
||||
<shvc:LoadingViewSlim IsLoading="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
@@ -7,7 +7,7 @@
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvco="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvg="using:Snap.Hutao.ViewModel.GachaLog"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
@@ -72,65 +72,67 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastOrangePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="0,6,0,0"
|
||||
Margin="0,3,0,0"
|
||||
Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastPurplePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@@ -152,65 +154,67 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastOrangePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="0,6,0,0"
|
||||
Margin="0,3,0,0"
|
||||
Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastPurplePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@@ -232,65 +236,67 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastOrangePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||
Text="{Binding LastOrangePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="0,6,0,0"
|
||||
Margin="0,3,0,0"
|
||||
Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
<ProgressBar
|
||||
Grid.ColumnSpan="2"
|
||||
MinHeight="40"
|
||||
Background="Transparent"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||
Opacity="0.15"
|
||||
Style="{StaticResource DefaultProgressBarStyle}"
|
||||
Value="{Binding LastPurplePull}"/>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||
Text="{Binding LastPurplePull}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@@ -298,6 +304,6 @@
|
||||
</DataTemplate>
|
||||
</FlipView.ItemTemplate>
|
||||
</FlipView>
|
||||
<shvco:LoadingViewSlim IsLoading="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}}"/>
|
||||
<shvc:LoadingViewSlim IsLoading="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Height="{StaticResource HomeAdaptiveCardHeight}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource AccentAcrylicInAppFillColorDefaultBrush}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ProgressRing IsActive="True"/>
|
||||
</StackPanel>
|
||||
</cwuc:Loading>
|
||||
|
||||
@@ -169,24 +169,10 @@
|
||||
DesiredWidth="300"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
SelectionMode="None">
|
||||
<shvca:LaunchGameCard Height="166" DataContext="{Binding LaunchGameViewModelSlim}"/>
|
||||
<shvca:LaunchGameCard Height="{StaticResource HomeAdaptiveCardHeight}" DataContext="{Binding LaunchGameViewModelSlim}"/>
|
||||
<shvca:GachaStatisticsCard DataContext="{Binding GachaLogViewModelSlim}"/>
|
||||
<shvca:AchievementCard DataContext="{Binding AchievementViewModelSlim}"/>
|
||||
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<FlipView Background="{x:Null}">
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="100/800"/>
|
||||
<TextBlock Text="12.5%"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Row="1" Text="Archive Name"/>
|
||||
</Grid>
|
||||
</FlipView>
|
||||
</Border>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<TextBlock Text="实时便笺"/>
|
||||
</Border>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就统计
|
||||
/// </summary>
|
||||
internal sealed class AchievementStatistics
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 完成进度描述 xxx/yyy
|
||||
/// </summary>
|
||||
public string FinishDescription { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 近期完成的成就
|
||||
/// </summary>
|
||||
public List<AchievementView> Achievements { get; set; } = default!;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ internal sealed class AchievementView : ObservableObject, IEntityWithMetadata<Mo
|
||||
Entity = entity;
|
||||
Inner = inner;
|
||||
|
||||
isChecked = (int)entity.Status >= 2;
|
||||
isChecked = (int)entity.Status >= (int)AchievementStatus.STATUS_FINISHED;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,7 +56,7 @@ internal sealed class AchievementView : ObservableObject, IEntityWithMetadata<Mo
|
||||
// Only update state when checked
|
||||
if (value)
|
||||
{
|
||||
Entity.Status = AchievementInfoStatus.STATUS_REWARD_TAKEN;
|
||||
Entity.Status = AchievementStatus.STATUS_REWARD_TAKEN;
|
||||
Entity.Time = DateTimeOffset.Now;
|
||||
OnPropertyChanged(nameof(Time));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
@@ -367,9 +368,9 @@ internal sealed class AchievementViewModel : Abstraction.ViewModel, INavigationR
|
||||
return;
|
||||
}
|
||||
|
||||
List<MetadataAchievement> rawAchievements = await metadataService.GetAchievementsAsync(CancellationToken).ConfigureAwait(false);
|
||||
List<MetadataAchievement> achievements = await metadataService.GetAchievementsAsync(CancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (TryGetAchievements(archive, rawAchievements, out List<AchievementView>? combined))
|
||||
if (TryGetAchievements(archive, achievements, out List<AchievementView>? combined))
|
||||
{
|
||||
// Assemble achievements on the UI thread.
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
@@ -436,9 +437,9 @@ internal sealed class AchievementViewModel : Abstraction.ViewModel, INavigationR
|
||||
|
||||
if (!string.IsNullOrEmpty(search))
|
||||
{
|
||||
if (search.Length == 5 && int.TryParse(search, out int entityId))
|
||||
if (search.Length == 5 && int.TryParse(search, out int achievementId))
|
||||
{
|
||||
Achievements.Filter = obj => ((AchievementView)obj).Inner.Id == entityId;
|
||||
Achievements.Filter = obj => ((AchievementView)obj).Inner.Id == achievementId;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 简化的成就视图模型
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed class AchievementViewModelSlim : Abstraction.ViewModelSlim<View.Page.AchievementPage>
|
||||
{
|
||||
private List<AchievementStatistics>? statisticsList;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的简化的成就视图模型
|
||||
/// </summary>
|
||||
@@ -16,4 +23,33 @@ internal sealed class AchievementViewModelSlim : Abstraction.ViewModelSlim<View.
|
||||
: base(serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统计列表
|
||||
/// </summary>
|
||||
public List<AchievementStatistics>? StatisticsList { get => statisticsList; set => SetProperty(ref statisticsList, value); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OpenUIAsync()
|
||||
{
|
||||
using (IServiceScope scope = ServiceProvider.CreateScope())
|
||||
{
|
||||
IMetadataService metadataService = scope.ServiceProvider.GetRequiredService<IMetadataService>();
|
||||
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<AchievementId, Model.Metadata.Achievement.Achievement> achievementMap = await metadataService
|
||||
.GetIdToAchievementMapAsync()
|
||||
.ConfigureAwait(false);
|
||||
List<AchievementStatistics> list = await scope.ServiceProvider
|
||||
.GetRequiredService<IAchievementService>()
|
||||
.GetAchievementStatisticsAsync(achievementMap)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
StatisticsList = list;
|
||||
IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
||||
|
||||
LaunchGameViewModelSlim = serviceProvider.GetRequiredService<Game.LaunchGameViewModelSlim>();
|
||||
GachaLogViewModelSlim = serviceProvider.GetRequiredService<GachaLog.GachaLogViewModelSlim>();
|
||||
AchievementViewModelSlim = serviceProvider.GetRequiredService<Achievement.AchievementViewModelSlim>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,6 +45,11 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
public GachaLog.GachaLogViewModelSlim GachaLogViewModelSlim { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 成就统计视图模型
|
||||
/// </summary>
|
||||
public Achievement.AchievementViewModelSlim AchievementViewModelSlim { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OpenUIAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user