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

右键显示缺项带图片

This commit is contained in:
mfkvfhpdx
2026-05-03 22:18:52 +08:00
parent 8f5532819a
commit ace17fcc7b
4 changed files with 186 additions and 18 deletions
@@ -352,7 +352,7 @@ internal sealed partial class CultivationService : ICultivationService
entryByInnerId[e.InnerId] = e;
}
Dictionary<uint, List<string>> unfinishedSegmentsByMaterial = [];
Dictionary<uint, List<(string SortKey, StatisticsConsumerMenuLine Line)>> unfinishedRowsByMaterial = [];
foreach ((CultivateEntry entry, CultivateItem item) in pairs.AsSpan())
{
@@ -361,33 +361,75 @@ internal sealed partial class CultivationService : ICultivationService
continue;
}
string name = FormatStatisticsConsumerEntryName(entry, context, entryByInnerId);
string segment = $"{name}×{item.Count}";
ref List<string>? list = ref CollectionsMarshal.GetValueRefOrAddDefault(unfinishedSegmentsByMaterial, item.ItemId, out _);
string sortKey = $"{FormatStatisticsConsumerEntryName(entry, context, entryByInnerId)}×{item.Count}";
StatisticsConsumerMenuLine line = CreateStatisticsConsumerMenuLine(entry, item, context, entryByInnerId);
ref List<(string SortKey, StatisticsConsumerMenuLine Line)>? list = ref CollectionsMarshal.GetValueRefOrAddDefault(unfinishedRowsByMaterial, item.ItemId, out _);
list ??= [];
list.Add(segment);
list.Add((sortKey, line));
}
foreach ((uint materialId, StatisticsCultivateItem stat) in resultItems)
{
if (MaterialIds.IsExcludedFromStatisticsConsumerMenu(materialId))
{
stat.StatisticsConsumerMenuLines = ImmutableArray.Create(SH.ViewPageCultivationStatisticsConsumerMenuExcluded);
stat.StatisticsConsumerMenuLines = ImmutableArray.Create(StatisticsConsumerMenuLine.Plain(SH.ViewPageCultivationStatisticsConsumerMenuExcluded));
continue;
}
if (unfinishedSegmentsByMaterial.TryGetValue(materialId, out List<string>? segments))
if (unfinishedRowsByMaterial.TryGetValue(materialId, out List<(string SortKey, StatisticsConsumerMenuLine Line)>? rows))
{
segments.Sort(StringComparer.Ordinal);
stat.StatisticsConsumerMenuLines = ImmutableArray.CreateRange(segments);
rows.Sort(static (a, b) => StringComparer.Ordinal.Compare(a.SortKey, b.SortKey));
stat.StatisticsConsumerMenuLines = ImmutableArray.CreateRange(rows.ConvertAll(static r => r.Line));
}
else
{
stat.StatisticsConsumerMenuLines = ImmutableArray.Create(SH.ViewPageCultivationStatisticsUnfinishedConsumersEmptyList);
stat.StatisticsConsumerMenuLines = ImmutableArray.Create(StatisticsConsumerMenuLine.Plain(SH.ViewPageCultivationStatisticsUnfinishedConsumersEmptyList));
}
}
}
private static StatisticsConsumerMenuLine CreateStatisticsConsumerMenuLine(
CultivateEntry entry,
CultivateItem item,
ICultivationMetadataContext context,
Dictionary<Guid, CultivateEntry> entryByInnerId)
{
string countSuffix = $"×{item.Count}";
switch (entry.Type)
{
case CultivateType.AvatarAndSkill:
{
ModelItem avatarItem = context.GetAvatarItem(entry.Id);
return StatisticsConsumerMenuLine.SingleIcon(avatarItem.Icon, avatarItem.Quality, avatarItem.Name, countSuffix);
}
case CultivateType.Weapon:
{
ModelItem weaponItem = context.GetWeaponItem(entry.Id);
if (entry.RelatedEntryId is Guid relatedId
&& entryByInnerId.TryGetValue(relatedId, out CultivateEntry? related)
&& related.Type is CultivateType.AvatarAndSkill)
{
ModelItem avatarItem = context.GetAvatarItem(related.Id);
return StatisticsConsumerMenuLine.AvatarAndWeapon(
avatarItem.Icon,
avatarItem.Quality,
avatarItem.Name,
weaponItem.Icon,
weaponItem.Quality,
weaponItem.Name,
countSuffix);
}
return StatisticsConsumerMenuLine.SingleIcon(weaponItem.Icon, weaponItem.Quality, weaponItem.Name, countSuffix);
}
default:
return StatisticsConsumerMenuLine.Plain($"{Material.Default.Name}{countSuffix}");
}
}
private static string FormatStatisticsConsumerEntryName(
CultivateEntry entry,
ICultivationMetadataContext context,
@@ -238,12 +238,52 @@
<ScrollViewer MaxHeight="320" MinWidth="220" Padding="12,10">
<ItemsControl ItemsSource="{Binding StatisticsConsumerMenuLines, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock
Margin="0,3"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind Mode=OneWay}"
TextWrapping="WrapWholeWords"/>
<DataTemplate x:DataType="shvcu:StatisticsConsumerMenuLine">
<Grid Margin="0,3">
<TextBlock
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind PlainMessage, Mode=OneWay}"
TextWrapping="WrapWholeWords"
Visibility="{x:Bind IsPlainMessage, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}"/>
<StackPanel
Orientation="Horizontal"
Spacing="4"
VerticalAlignment="Center"
Visibility="{x:Bind ShowRichRow, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<shuxc:ItemIcon
Width="28"
Height="28"
Icon="{x:Bind LeadingIcon, Mode=OneWay}"
Quality="{x:Bind LeadingQuality, Mode=OneWay}"/>
<TextBlock
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind FirstName, Mode=OneWay}"/>
<StackPanel
Orientation="Horizontal"
Spacing="4"
VerticalAlignment="Center"
Visibility="{x:Bind HasSecondIcon, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<TextBlock
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind BetweenSeparator, Mode=OneWay}"/>
<shuxc:ItemIcon
Width="28"
Height="28"
Icon="{x:Bind SecondIcon, Mode=OneWay}"
Quality="{x:Bind SecondQuality, Mode=OneWay}"/>
<TextBlock
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind SecondName, Mode=OneWay}"/>
</StackPanel>
<TextBlock
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{x:Bind CountSuffix, Mode=OneWay}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
@@ -0,0 +1,86 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
namespace Snap.Hutao.ViewModel.Cultivation;
/// <summary>
/// 材料统计右键浮层中一行「未完成」养成条目:名称前展示角色/武器图标。
/// </summary>
internal sealed class StatisticsConsumerMenuLine
{
private StatisticsConsumerMenuLine()
{
}
public bool IsPlainMessage { get; private init; }
public string? PlainMessage { get; private init; }
public bool ShowRichRow => !IsPlainMessage;
public Uri LeadingIcon { get; private init; } = default!;
public QualityType LeadingQuality { get; private init; }
public bool HasSecondIcon { get; private init; }
public Uri SecondIcon { get; private init; } = default!;
public QualityType SecondQuality { get; private init; }
public string FirstName { get; private init; } = string.Empty;
/// <summary>双名称行中间分隔(与武器关联条目的「角色·武器」展示一致,使用间隔号)。</summary>
public string BetweenSeparator { get; private init; } = "\u00B7";
public string? SecondName { get; private init; }
public string CountSuffix { get; private init; } = string.Empty;
public static StatisticsConsumerMenuLine Plain(string message)
{
return new()
{
IsPlainMessage = true,
PlainMessage = message,
};
}
public static StatisticsConsumerMenuLine SingleIcon(Uri icon, QualityType quality, string name, string countSuffix)
{
return new()
{
LeadingIcon = icon,
LeadingQuality = quality,
FirstName = name,
CountSuffix = countSuffix,
HasSecondIcon = false,
SecondIcon = default!,
SecondQuality = QualityType.QUALITY_NONE,
};
}
public static StatisticsConsumerMenuLine AvatarAndWeapon(
Uri avatarIcon,
QualityType avatarQuality,
string avatarName,
Uri weaponIcon,
QualityType weaponQuality,
string weaponName,
string countSuffix)
{
return new()
{
LeadingIcon = avatarIcon,
LeadingQuality = avatarQuality,
FirstName = avatarName,
HasSecondIcon = true,
SecondIcon = weaponIcon,
SecondQuality = weaponQuality,
SecondName = weaponName,
CountSuffix = countSuffix,
};
}
}
@@ -68,9 +68,9 @@ internal sealed class StatisticsCultivateItem
public bool IsToday { get => Inner.IsItemOfToday(offset, true); }
/// <summary>
/// 材料统计右键浮层中按行展示的「未完成」养成条目(每人一行,<c>名×数量</c>)。
/// 材料统计右键浮层中按行展示的「未完成」养成条目(每人一行,名称前为角色/武器图标,<c>名×数量</c>)。
/// </summary>
public ImmutableArray<string> StatisticsConsumerMenuLines { get; set; }
public ImmutableArray<StatisticsConsumerMenuLine> StatisticsConsumerMenuLines { get; set; }
internal bool ExcludedFromPresentation { get; set; }