This commit is contained in:
DismissedLight
2024-07-11 16:57:28 +08:00
parent c3efd8d806
commit 0c0290c446
43 changed files with 284 additions and 228 deletions

View File

@@ -13,7 +13,7 @@ namespace Snap.Hutao.Model.Entity;
/// 成就存档
/// </summary>
[Table("achievement_archives")]
internal sealed class AchievementArchive : ISelectable,
internal sealed partial class AchievementArchive : ISelectable,
IAdvancedCollectionViewItem,
IMappingFrom<AchievementArchive, string>
{
@@ -43,12 +43,4 @@ internal sealed class AchievementArchive : ISelectable,
{
return new() { Name = name };
}
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default!,
};
}
}

View File

@@ -14,7 +14,7 @@ namespace Snap.Hutao.Model.Entity;
/// </summary>
[HighQuality]
[Table("cultivate_projects")]
internal sealed class CultivateProject : ISelectable,
internal sealed partial class CultivateProject : ISelectable,
IAdvancedCollectionViewItem,
IMappingFrom<CultivateProject, string, string>
{
@@ -50,12 +50,4 @@ internal sealed class CultivateProject : ISelectable,
{
return new() { Name = name, AttachedUid = attachedUid };
}
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default,
};
}
}

View File

@@ -42,12 +42,4 @@ internal sealed partial class GachaArchive : ISelectable,
{
return new() { Uid = uid };
}
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default,
};
}
}

View File

@@ -17,7 +17,7 @@ namespace Snap.Hutao.Model.Entity;
/// </summary>
[HighQuality]
[Table("game_accounts")]
internal sealed class GameAccount : ObservableObject,
internal sealed partial class GameAccount : ObservableObject,
IAppDbEntity,
IReorderable,
IAdvancedCollectionViewItem,
@@ -82,12 +82,4 @@ internal sealed class GameAccount : ObservableObject,
Name = name;
OnPropertyChanged($"{nameof(Name)}");
}
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
_ => default,
};
}
}

View File

@@ -117,12 +117,4 @@ internal partial class Avatar : INameQualityAccess,
IsUp = isUp,
};
}
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
_ => default,
};
}
}

View File

@@ -11,7 +11,7 @@ namespace Snap.Hutao.Model.Metadata.Monster;
/// <summary>
/// 敌对生物
/// </summary>
internal sealed class Monster : IAdvancedCollectionViewItem
internal sealed partial class Monster : IAdvancedCollectionViewItem
{
internal const uint MaxLevel = 100;
@@ -90,12 +90,4 @@ internal sealed class Monster : IAdvancedCollectionViewItem
/// </summary>
[JsonIgnore]
public List<DisplayItem>? DropsView { get; set; }
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
_ => default,
};
}
}

View File

@@ -106,12 +106,4 @@ internal sealed partial class Weapon : INameQualityAccess,
IsUp = isUp,
};
}
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
_ => default,
};
}
}

View File

@@ -1568,6 +1568,12 @@
<data name="ViewModelAvatarPropertyShowcaseNotOpen" xml:space="preserve">
<value>角色展柜尚未开启,请前往游戏操作后重试</value>
</data>
<data name="ViewModelAvatatPropertyExportTextError" xml:space="preserve">
<value>复制角色详情失败</value>
</data>
<data name="ViewModelAvatatPropertyExportTextSuccess" xml:space="preserve">
<value>复制角色详情成功</value>
</data>
<data name="ViewModelComplexReliquarySetViewEmptyName" xml:space="preserve">
<value>无圣遗物或散件</value>
</data>
@@ -1889,6 +1895,9 @@
<data name="ViewPageAvatarPropertyExportAsImage" xml:space="preserve">
<value>导出图片</value>
</data>
<data name="ViewPageAvatarPropertyExportToTextLabel" xml:space="preserve">
<value>导出文本到剪贴板</value>
</data>
<data name="ViewPageAvatarPropertyHeader" xml:space="preserve">
<value>角色属性</value>
</data>

View File

@@ -10,6 +10,13 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder;
internal static class EquipViewBuilderExtension
{
public static TBuilder SetEquipType<TBuilder, T>(this TBuilder builder, EquipType equipType)
where TBuilder : IEquipViewBuilder<T>
where T : EquipView
{
return builder.Configure(b => b.View.EquipType = equipType);
}
public static TBuilder SetLevel<TBuilder, T>(this TBuilder builder, string level)
where TBuilder : IEquipViewBuilder<T>
where T : EquipView

View File

@@ -22,6 +22,12 @@ internal static class ReliquaryViewBuilderExtension
return builder.SetDescription<TBuilder, ReliquaryView>(description);
}
public static TBuilder SetEquipType<TBuilder>(this TBuilder builder, EquipType equipType)
where TBuilder : IReliquaryViewBuilder
{
return builder.SetEquipType<TBuilder, ReliquaryView>(equipType);
}
public static TBuilder SetIcon<TBuilder>(this TBuilder builder, Uri icon)
where TBuilder : IReliquaryViewBuilder
{
@@ -63,4 +69,10 @@ internal static class ReliquaryViewBuilderExtension
{
return builder.Configure(b => b.View.SecondarySubProperties = secondarySubProperties);
}
public static TBuilder SetSetName<TBuilder>(this TBuilder builder, string setName)
where TBuilder : IReliquaryViewBuilder
{
return builder.Configure(b => b.View.SetName = setName);
}
}

View File

@@ -37,6 +37,12 @@ internal static class WeaponViewBuilderExtension
return builder.SetDescription<TBuilder, WeaponView>(description);
}
public static TBuilder SetEquipType<TBuilder>(this TBuilder builder, EquipType equipType)
where TBuilder : IWeaponViewBuilder
{
return builder.SetEquipType<TBuilder, WeaponView>(equipType);
}
public static TBuilder SetIcon<TBuilder>(this TBuilder builder, Uri icon)
where TBuilder : IWeaponViewBuilder
{
@@ -85,7 +91,7 @@ internal static class WeaponViewBuilderExtension
return builder.SetQuality<TBuilder, WeaponView>(quality);
}
public static TBuilder SetSubProperty<TBuilder>(this TBuilder builder, NameDescription subProperty)
public static TBuilder SetSubProperty<TBuilder>(this TBuilder builder, NameValue<string> subProperty)
where TBuilder : IWeaponViewBuilder
{
return builder.Configure(b => b.View.SubProperty = subProperty);

View File

@@ -102,17 +102,17 @@ internal sealed class SummaryAvatarFactory
WeaponStat? mainStat = equip.Flat.WeaponStats?.ElementAtOrDefault(0);
WeaponStat? subStat = equip.Flat.WeaponStats?.ElementAtOrDefault(1);
NameDescription subProperty;
NameValue<string> subProperty;
if (subStat is null)
{
subProperty = NameDescription.Default;
subProperty = NameValueDefaults.String;
}
else
{
float statValue = subStat.AppendPropId.GetFormatMethod() is FormatMethod.Percent
? subStat.StatValue / 100F
: subStat.StatValue;
subProperty = FightPropertyFormat.ToNameDescription(subStat.AppendPropId, statValue);
subProperty = FightPropertyFormat.ToNameValue(subStat.AppendPropId, statValue);
}
ArgumentNullException.ThrowIfNull(equip.Weapon);
@@ -123,6 +123,7 @@ internal sealed class SummaryAvatarFactory
.SetDescription(weapon.Description)
.SetLevel(LevelFormat.Format(equip.Weapon.Level))
.SetQuality(weapon.Quality)
.SetEquipType(EquipType.EQUIP_WEAPON)
.SetMainProperty(mainStat)
.SetId(weapon.Id)
.SetLevelNumber(equip.Weapon.Level)

View File

@@ -17,6 +17,7 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
internal sealed partial class SummaryFactory : ISummaryFactory
{
private readonly IMetadataService metadataService;
private readonly ITaskContext taskContext;
/// <inheritdoc/>
public async ValueTask<Summary> CreateAsync(IEnumerable<Model.Entity.AvatarInfo> avatarInfos, CancellationToken token)
@@ -34,9 +35,13 @@ internal sealed partial class SummaryFactory : ISummaryFactory
.ThenBy(a => a.Weapon?.WeaponType)
.ThenByDescending(a => a.FetterLevel);
IList<AvatarView> views = [.. avatars];
await taskContext.SwitchToMainThreadAsync();
return new()
{
Avatars = [.. avatars],
Avatars = new(views, true),
};
}
}

View File

@@ -17,6 +17,7 @@ internal sealed class SummaryFactoryMetadataContext : IMetadataContext,
IMetadataDictionaryIdWeaponSource,
IMetadataDictionaryIdReliquaryAffixWeightSource,
IMetadataDictionaryIdReliquaryMainPropertySource,
IMetadataDictionaryIdReliquarySetSource,
IMetadataDictionaryIdReliquarySubAffixSource,
IMetadataDictionaryIdReliquarySource,
IMetadataListReliquaryMainAffixLevelSource
@@ -31,6 +32,8 @@ internal sealed class SummaryFactoryMetadataContext : IMetadataContext,
public Dictionary<ReliquarySubAffixId, ReliquarySubAffix> IdReliquarySubAffixMap { get; set; } = default!;
public Dictionary<ReliquarySetId, ReliquarySet> IdReliquarySetMap { get; set; } = default!;
public List<ReliquaryMainAffixLevel> ReliquaryMainAffixLevels { get; set; } = default!;
public Dictionary<ReliquaryId, MetadataReliquary> IdReliquaryMap { get; set; } = default!;

View File

@@ -36,6 +36,7 @@ internal sealed class SummaryReliquaryFactory
public ReliquaryView Create()
{
MetadataReliquary reliquary = metadataContext.IdReliquaryMap[equip.ItemId];
ReliquarySet reliquarySet = metadataContext.IdReliquarySetMap[reliquary.SetId];
ArgumentNullException.ThrowIfNull(equip.Reliquary);
List<ReliquarySubProperty> subProperties = equip.Reliquary.AppendPropIdList.EmptyIfNull().SelectList(CreateSubProperty);
@@ -45,7 +46,9 @@ internal sealed class SummaryReliquaryFactory
.SetIcon(RelicIconConverter.IconNameToUri(reliquary.Icon))
.SetDescription(reliquary.Description)
.SetLevel($"+{equip.Reliquary.Level - 1U}")
.SetQuality(reliquary.RankLevel);
.SetQuality(reliquary.RankLevel)
.SetEquipType(reliquary.EquipType)
.SetSetName(reliquarySet.Name);
int affixCount = GetSecondaryAffixCount(reliquary, equip.Reliquary);

View File

@@ -18,13 +18,6 @@ internal interface IGameServiceFacade
/// 游戏内账号集合
/// </summary>
ObservableReorderableDbCollection<GameAccount> GameAccountCollection { get; }
/// <summary>
/// 将账号绑定到对应的Uid
/// 清除老账号的绑定状态
/// </summary>
/// <param name="gameAccount">游戏内账号</param>
/// <param name="uid">uid</param>
ValueTask AttachGameAccountToUidAsync(GameAccount gameAccount, string uid);
ValueTask<GameAccount?> DetectGameAccountAsync(SchemeType scheme);

View File

@@ -0,0 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdReliquarySetSource
{
Dictionary<ReliquarySetId, ReliquarySet> IdReliquarySetMap { get; set; }
}

View File

@@ -86,6 +86,11 @@ internal static class MetadataServiceContextExtension
dictionaryIdReliquaryMainPropertySource.IdReliquaryMainPropertyMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false);
}
if (context is IMetadataDictionaryIdReliquarySetSource dictionaryIdReliquarySetSource)
{
dictionaryIdReliquarySetSource.IdReliquarySetMap = await metadataService.GetIdToReliquarySetMapAsync(token).ConfigureAwait(false);
}
if (context is IMetadataDictionaryIdReliquarySubAffixSource dictionaryIdReliquarySubAffixSource)
{
dictionaryIdReliquarySubAffixSource.IdReliquarySubAffixMap = await metadataService.GetIdToReliquarySubAffixMapAsync(token).ConfigureAwait(false);

View File

@@ -86,6 +86,11 @@ internal static class MetadataServiceDictionaryExtension
return metadataService.FromCacheAsDictionaryAsync<ReliquaryMainAffix, ReliquaryMainAffixId, FightProperty>(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token);
}
public static ValueTask<Dictionary<ReliquarySetId, ReliquarySet>> GetIdToReliquarySetMapAsync(this IMetadataService metadataService, CancellationToken token = default)
{
return metadataService.FromCacheAsDictionaryAsync<ReliquarySetId, ReliquarySet>(FileNameReliquarySet, r => r.SetId, token);
}
public static ValueTask<Dictionary<ReliquarySubAffixId, ReliquarySubAffix>> GetIdToReliquarySubAffixMapAsync(this IMetadataService metadataService, CancellationToken token = default)
{
return metadataService.FromCacheAsDictionaryAsync<ReliquarySubAffixId, ReliquarySubAffix>(FileNameReliquarySubAffix, a => a.Id, token);

View File

@@ -8,20 +8,15 @@ namespace Snap.Hutao.Service.Notification;
/// <inheritdoc/>
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Singleton, typeof(IInfoBarService))]
internal sealed class InfoBarService : IInfoBarService
internal sealed partial class InfoBarService : IInfoBarService
{
private readonly ILogger<InfoBarService> logger;
private readonly ITaskContext taskContext;
private ObservableCollection<InfoBarOptions>? collection;
public InfoBarService(IServiceProvider serviceProvider)
{
logger = serviceProvider.GetRequiredService<ILogger<InfoBarService>>();
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
}
/// <inheritdoc/>
public ObservableCollection<InfoBarOptions> Collection
{

View File

@@ -315,7 +315,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Snap.Hutao.SourceGeneration" Version="1.1.1">
<PackageReference Include="Snap.Hutao.SourceGeneration" Version="1.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -556,12 +556,16 @@
Content="{shuxm:ResourceString Name=ViewPageAvatarPropertyRefreshTimeToggle}"/>
</StackPanel>
</CommandBar.Content>
<AppBarButton
Command="{Binding ExportToTextCommand}"
Icon="{shuxm:FontIcon Glyph=&#xEDE1;}"
Label="{shuxm:ResourceString Name=ViewPageAvatarPropertyExportToTextLabel}"/>
<AppBarButton Icon="{shuxm:FontIcon Glyph=&#xE8EF;}" Label="{shuxm:ResourceString Name=ViewPageCultivateCalculate}">
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem
Command="{Binding CultivateCommand}"
CommandParameter="{Binding SelectedAvatar}"
CommandParameter="{Binding Summary.Avatars.CurrentItem}"
Text="{shuxm:ResourceString Name=ViewPageAvatarPropertyCalculateCurrent}"/>
<MenuFlyoutItem Command="{Binding BatchCultivateCommand}" Text="{shuxm:ResourceString Name=ViewPageAvatarPropertyCalculateAll}"/>
</MenuFlyout>
@@ -592,7 +596,7 @@
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
ItemTemplate="{StaticResource AvatarGridViewTemplate}"
ItemsSource="{Binding Summary.Avatars}"
SelectedItem="{Binding SelectedAvatar, Mode=TwoWay}"/>
SelectedItem="{Binding Summary.Avatars.CurrentItem, Mode=TwoWay}"/>
</cwcont:Case>
<cwcont:Case Value="List">
<SplitView
@@ -606,7 +610,7 @@
Padding="{ThemeResource ListViewInSplitPanePadding}"
ItemTemplate="{StaticResource AvatarListViewTemplate}"
ItemsSource="{Binding Summary.Avatars}"
SelectedItem="{Binding SelectedAvatar, Mode=TwoWay}"/>
SelectedItem="{Binding Summary.Avatars.CurrentItem, Mode=TwoWay}"/>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
@@ -638,7 +642,7 @@
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding SelectedAvatar.NameCard}"
Source="{Binding Summary.Avatars.CurrentItem.NameCard}"
Stretch="UniformToFill"/>
</cwcont:ConstrainedBox>
<Border
@@ -658,18 +662,18 @@
</Grid.ColumnDefinitions>
<shuxc:ItemIcon
cw:Effects.Shadow="{ThemeResource CompatCardShadow}"
Icon="{Binding SelectedAvatar.Icon}"
Quality="{Binding SelectedAvatar.Quality}"/>
Icon="{Binding Summary.Avatars.CurrentItem.Icon}"
Quality="{Binding Summary.Avatars.CurrentItem.Quality}"/>
<StackPanel Grid.Column="1" Margin="16,0,0,0">
<TextBlock
Foreground="#FFFFFFFF"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding SelectedAvatar.Name}"/>
Text="{Binding Summary.Avatars.CurrentItem.Name}"/>
<TextBlock
Margin="0,4,0,0"
Foreground="#FFFFFFFF"
Style="{StaticResource BaseTextBlockStyle}"
Text="{Binding SelectedAvatar.Level}"/>
Text="{Binding Summary.Avatars.CurrentItem.Level}"/>
<StackPanel Margin="0,2,0,0" Orientation="Horizontal">
<Image
Width="16"
@@ -681,7 +685,7 @@
Foreground="#FFFFFFFF"
HorizontalTextAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding SelectedAvatar.FetterLevel}"
Text="{Binding Summary.Avatars.CurrentItem.FetterLevel}"
TextAlignment="Center"
TextTrimming="None"
TextWrapping="NoWrap"/>
@@ -691,7 +695,7 @@
<Grid
Margin="0,16,0,0"
HorizontalAlignment="Left"
DataContext="{Binding SelectedAvatar.Weapon}">
DataContext="{Binding Summary.Avatars.CurrentItem.Weapon}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
@@ -723,7 +727,7 @@
Margin="0,2,0,0"
Padding="12"
Header="{Binding SubProperty.Name}">
<TextBlock Text="{Binding SubProperty.Description}"/>
<TextBlock Text="{Binding SubProperty.Value}"/>
</cwcont:SettingsCard>
<shuxct:DescriptionTextBlock
MaxWidth="320"
@@ -757,7 +761,7 @@
HorizontalAlignment="Right"
Foreground="#FFFFFFFF"
Style="{StaticResource TitleTextBlockStyle}"
Text="{Binding SelectedAvatar.ScoreFormatted}"/>
Text="{Binding Summary.Avatars.CurrentItem.ScoreFormatted}"/>
<TextBlock
HorizontalAlignment="Right"
Foreground="#FFFFFFFF"
@@ -769,7 +773,7 @@
HorizontalAlignment="Right"
Foreground="#FFFFFFFF"
Style="{StaticResource TitleTextBlockStyle}"
Text="{Binding SelectedAvatar.CritScoreFormatted}"/>
Text="{Binding Summary.Avatars.CurrentItem.CritScoreFormatted}"/>
<TextBlock
HorizontalAlignment="Right"
Foreground="#FFFFFFFF"
@@ -784,7 +788,7 @@
Margin="16"
VerticalAlignment="Bottom"
ItemTemplate="{StaticResource AvatarSkillTemplate}"
ItemsSource="{Binding SelectedAvatar.Skills}"/>
ItemsSource="{Binding Summary.Avatars.CurrentItem.Skills}"/>
<ItemsControl
Grid.Row="1"
@@ -792,7 +796,7 @@
Margin="16"
ItemTemplate="{StaticResource AvatarConstellationTemplate}"
ItemsPanel="{StaticResource HorizontalStackPanelSpacing0Template}"
ItemsSource="{Binding SelectedAvatar.Constellations}"/>
ItemsSource="{Binding Summary.Avatars.CurrentItem.Constellations}"/>
</Grid>
</Border>
@@ -808,14 +812,14 @@
<ItemsControl
Margin="0,-1,0,0"
ItemTemplate="{StaticResource AvatarPropertyTemplate}"
ItemsSource="{Binding SelectedAvatar.Properties}"/>
ItemsSource="{Binding Summary.Avatars.CurrentItem.Properties}"/>
</Border>
</Expander>
<!-- 圣遗物 -->
<ItemsControl
Margin="16,16,16,0"
ItemTemplate="{StaticResource AvatarReliquaryTemplate}"
ItemsSource="{Binding SelectedAvatar.Reliquaries}"/>
ItemsSource="{Binding Summary.Avatars.CurrentItem.Reliquaries}"/>
</StackPanel>
</ScrollViewer>
</SplitView.Content>

View File

@@ -333,11 +333,11 @@
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
ItemTemplate="{StaticResource SpiralAbyssListTemplate}"
ItemsSource="{Binding SpiralAbyssEntries}"
SelectedItem="{Binding SelectedView, Mode=TwoWay}"/>
SelectedItem="{Binding SpiralAbyssEntries.CurrentItem, Mode=TwoWay}"/>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
<StackPanel DataContext="{Binding SelectedView}">
<StackPanel DataContext="{Binding SpiralAbyssEntries.CurrentItem}">
<Grid Margin="16,12,16,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>

View File

@@ -11,6 +11,8 @@
<UserControl.Resources>
<Thickness x:Key="SettingsCardPadding">16,8</Thickness>
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
<DataTemplate x:Key="BaseValueTemplate">
<cwc:SettingsCard

View File

@@ -7,16 +7,10 @@ using Snap.Hutao.ViewModel.Wiki;
namespace Snap.Hutao.UI.Xaml.View.Specialized;
/// <summary>
/// 基础数值滑动条
/// </summary>
[DependencyProperty("BaseValueInfo", typeof(BaseValueInfo))]
[DependencyProperty("IsPromoteVisible", typeof(bool), true)]
internal sealed partial class BaseValueSlider : UserControl
{
/// <summary>
/// 构造一个新的基础数值滑动条
/// </summary>
public BaseValueSlider()
{
InitializeComponent();

View File

@@ -144,6 +144,7 @@
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="HoYoLAB"
Visibility="{Binding IsOversea}"/>
<StackPanel

View File

@@ -11,7 +11,7 @@ using Snap.Hutao.UI.Xaml.Data;
namespace Snap.Hutao.ViewModel.Achievement;
internal sealed class AchievementGoalView : ObservableObject,
internal sealed partial class AchievementGoalView : ObservableObject,
INameIcon,
IAdvancedCollectionViewItem,
IMappingFrom<AchievementGoalView, AchievementGoal>
@@ -49,14 +49,4 @@ internal sealed class AchievementGoalView : ObservableObject,
FinishDescription = AchievementStatistics.Format(statistics.Finished, statistics.TotalCount, out double finishPercent);
FinishPercent = finishPercent;
}
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
nameof(Order) => Order,
nameof(FinishPercent) => FinishPercent,
_ => default,
};
}
}

View File

@@ -8,11 +8,7 @@ using Snap.Hutao.UI.Xaml.Data;
namespace Snap.Hutao.ViewModel.Achievement;
/// <summary>
/// 用于视图绑定的成就
/// </summary>
[HighQuality]
internal sealed class AchievementView : ObservableObject,
internal sealed partial class AchievementView : ObservableObject,
IEntityAccessWithMetadata<Model.Entity.Achievement, Model.Metadata.Achievement.Achievement>,
IAdvancedCollectionViewItem
{
@@ -57,15 +53,4 @@ internal sealed class AchievementView : ObservableObject,
{
get => $"{Entity.Time.ToLocalTime():yyyy.MM.dd HH:mm:ss}";
}
public object? GetPropertyValue(string propertyName)
{
return propertyName switch
{
nameof(Order) => Order,
nameof(IsChecked) => IsChecked,
nameof(Time) => Time,
_ => default,
};
}
}

View File

@@ -13,10 +13,12 @@ using Snap.Hutao.Service.Cultivation;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.UI.Xaml.Control;
using Snap.Hutao.UI.Xaml.Data;
using Snap.Hutao.UI.Xaml.View.Dialog;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
using Snap.Hutao.Web.Response;
using System.Globalization;
using CalculatorAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalculatorBatchConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.BatchConsumption;
using CalculatorClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
@@ -26,10 +28,6 @@ using CalculatorItemHelper = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.ItemH
namespace Snap.Hutao.ViewModel.AvatarProperty;
/// <summary>
/// 角色属性视图模型
/// </summary>
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, IRecipient<UserAndUidChangedMessage>
@@ -38,14 +36,13 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
private readonly IAppResourceProvider appResourceProvider;
private readonly ICultivationService cultivationService;
private readonly IAvatarInfoService avatarInfoService;
private readonly IClipboardProvider clipboardInterop;
private readonly IClipboardProvider clipboardProvider;
private readonly CalculatorClient calculatorClient;
private readonly IInfoBarService infoBarService;
private readonly ITaskContext taskContext;
private readonly IUserService userService;
private Summary? summary;
private AvatarView? selectedAvatar;
private enum CultivateCoreResult
{
@@ -54,17 +51,8 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
SaveConsumptionFailed,
}
/// <summary>
/// 简述对象
/// </summary>
public Summary? Summary { get => summary; set => SetProperty(ref summary, value); }
/// <summary>
/// 选中的角色
/// </summary>
public AvatarView? SelectedAvatar { get => selectedAvatar; set => SetProperty(ref selectedAvatar, value); }
/// <inheritdoc/>
public void Receive(UserAndUidChangedMessage message)
{
if (message.UserAndUid is { } userAndUid)
@@ -133,11 +121,11 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
}
(RefreshResultKind result, Summary? summary) = summaryResult;
if (result == RefreshResultKind.Ok)
if (result is RefreshResultKind.Ok)
{
await taskContext.SwitchToMainThreadAsync();
Summary = summary;
SelectedAvatar = Summary?.Avatars.FirstOrDefault();
Summary?.Avatars.MoveCurrentToFirstOrDefault();
}
else
{
@@ -313,4 +301,22 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
return true;
}
[Command("ExportToTextCommand")]
private void ExportToText()
{
if (Summary is not { Avatars.CurrentItem: { } avatar })
{
return;
}
if (clipboardProvider.SetText(AvatarViewTextTemplating.GetTemplatedText(avatar)))
{
infoBarService.Success(SH.ViewModelAvatatPropertyExportTextSuccess);
}
else
{
infoBarService.Warning(SH.ViewModelAvatatPropertyExportTextError);
}
}
}

View File

@@ -5,13 +5,16 @@ using Snap.Hutao.Model;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.UI.Xaml.Data;
namespace Snap.Hutao.ViewModel.AvatarProperty;
/// <summary>
/// 角色信息
/// </summary>
internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableAvatar>
internal sealed partial class AvatarView : INameIconSide,
ICalculableSource<ICalculableAvatar>,
IAdvancedCollectionViewItem
{
/// <summary>
/// 名称

View File

@@ -0,0 +1,112 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model;
using Snap.Hutao.Model.Intrinsic;
using System.Runtime.InteropServices;
using System.Text;
namespace Snap.Hutao.ViewModel.AvatarProperty;
internal static class AvatarViewTextTemplating
{
public static string GetTemplatedText(AvatarView avatar)
{
string avatarTemplate = $"""
// {avatar.Name} [{avatar.Level}, ☆{avatar.Quality:D}, C{avatar.Constellations.Where(c => c.IsActivated).Count()}] [{FormatSkills(avatar.Skills)}]
""";
string weaponTemplate = avatar.Weapon is { } weapon
? $"""
// ---------------------
// {weapon.Name} [{weapon.Level}, ☆{weapon.Quality:D}, R{weapon.AffixLevelNumber}]
// [{weapon.MainProperty.Name}: {weapon.MainProperty.Value}] [{weapon.SubProperty.Name}: {weapon.SubProperty.Value}]
"""
: string.Empty;
string propertiesTemplate = avatar.Properties.Count > 0
? $"""
// ---------------------
{FormatProperties(avatar.Properties)}
"""
: string.Empty;
string reliquariesTemplate = avatar.Reliquaries.Count > 0
? $"""
// ---------------------
{FormatReliquaries(avatar.Reliquaries)}
"""
: string.Empty;
return $"""
// =====================
{avatarTemplate}{weaponTemplate}{propertiesTemplate}{reliquariesTemplate}// =====================
""";
}
private static string FormatSkills(List<SkillView> skills)
{
StringBuilder result = new();
Span<SkillView> skillSpan = CollectionsMarshal.AsSpan(skills);
for (int index = 0; index < skillSpan.Length; index++)
{
ref readonly SkillView skill = ref skillSpan[index];
result.Append(skill.Level);
if (index < skillSpan.Length - 1)
{
result.Append(", ");
}
}
return result.ToString();
}
private static string FormatProperties(List<AvatarProperty> properties)
{
StringBuilder result = new();
foreach (ref readonly AvatarProperty property in CollectionsMarshal.AsSpan(properties))
{
result.Append("// [").Append(property.Name).Append(": ").Append(property.Value).Append(']').AppendLine();
}
return result.ToString();
}
[SuppressMessage("", "CA1305")]
private static string FormatReliquaries(List<ReliquaryView> reliquaries)
{
StringBuilder result = new();
foreach (ref readonly ReliquaryView reliquary in CollectionsMarshal.AsSpan(reliquaries))
{
NameValue<string>? mainProperty = reliquary.MainProperty;
result.Append($"""
// {ReliquaryEmoji(reliquary.EquipType)} {mainProperty?.Name}: {mainProperty?.Value} [☆{reliquary.Quality:D} {reliquary.Level} {reliquary.SetName}]
""");
result.Append("// ");
foreach (ref readonly ReliquaryComposedSubProperty subProperty in CollectionsMarshal.AsSpan(reliquary.ComposedSubProperties))
{
result.Append('[').Append(subProperty.Name).Append(": ").Append(subProperty.Value).Append(']');
}
result.AppendLine();
}
return result.ToString();
}
private static string ReliquaryEmoji(EquipType type)
{
return type switch
{
EquipType.EQUIP_BRACER => "🌷",
EquipType.EQUIP_NECKLACE => "🪶",
EquipType.EQUIP_SHOES => "⏳",
EquipType.EQUIP_RING => "🍷",
EquipType.EQUIP_DRESS => "👑",
_ => string.Empty,
};
}
}

View File

@@ -26,4 +26,6 @@ internal abstract class EquipView : NameIconDescription
/// 主属性
/// </summary>
public NameValue<string> MainProperty { get; set; } = default!;
internal EquipType EquipType { get; set; }
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model;
using Snap.Hutao.Model.Intrinsic;
namespace Snap.Hutao.ViewModel.AvatarProperty;

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
namespace Snap.Hutao.ViewModel.AvatarProperty;
/// <summary>
@@ -33,4 +35,6 @@ internal sealed class ReliquaryView : EquipView
/// 评分
/// </summary>
internal float Score { get; set; }
internal string SetName { get; set; } = default!;
}

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.UI.Xaml.Data;
namespace Snap.Hutao.ViewModel.AvatarProperty;
/// <summary>
@@ -9,13 +11,7 @@ namespace Snap.Hutao.ViewModel.AvatarProperty;
[HighQuality]
internal sealed class Summary
{
/// <summary>
/// 角色列表
/// </summary>
public List<AvatarView> Avatars { get; set; } = default!;
public AdvancedCollectionView<AvatarView> Avatars { get; set; } = default!;
/// <summary>
/// 服务器消息
/// </summary>
public string Message { get; set; } = default!;
}

View File

@@ -17,7 +17,7 @@ internal sealed class WeaponView : EquipView, ICalculableSource<ICalculableWeapo
/// <summary>
/// 副属性
/// </summary>
public NameDescription SubProperty { get; set; } = default!;
public NameValue<string> SubProperty { get; set; } = default!;
/// <summary>
/// 精炼等级

View File

@@ -7,10 +7,6 @@ using Snap.Hutao.Web.Hutao.SpiralAbyss;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 胡桃数据库视图模型
/// </summary>
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
internal sealed partial class HutaoDatabaseViewModel : Abstraction.ViewModel

View File

@@ -9,7 +9,7 @@ namespace Snap.Hutao.ViewModel.GachaLog;
/// 历史卡池概览
/// </summary>
[HighQuality]
internal sealed class HistoryWish : Wish, IAdvancedCollectionViewItem
internal sealed partial class HistoryWish : Wish, IAdvancedCollectionViewItem
{
/// <summary>
/// 版本
@@ -45,12 +45,4 @@ internal sealed class HistoryWish : Wish, IAdvancedCollectionViewItem
/// 三星Up
/// </summary>
public List<StatisticsItem> BlueList { get; set; } = default!;
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default,
};
}
}

View File

@@ -9,21 +9,17 @@ using Snap.Hutao.Service.Navigation;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.SpiralAbyss;
using Snap.Hutao.Service.User;
using Snap.Hutao.UI.Xaml.Data;
using Snap.Hutao.UI.Xaml.View.Dialog;
using Snap.Hutao.UI.Xaml.View.Page;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Hutao.SpiralAbyss;
using Snap.Hutao.Web.Hutao.SpiralAbyss.Post;
using System.Collections.ObjectModel;
namespace Snap.Hutao.ViewModel.SpiralAbyss;
/// <summary>
/// 深渊记录视图模型
/// </summary>
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecipient<UserAndUidChangedMessage>
@@ -38,18 +34,12 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
private readonly HutaoDatabaseViewModel hutaoDatabaseViewModel;
private readonly HutaoUserOptions hutaoUserOptions;
private ObservableCollection<SpiralAbyssView>? spiralAbyssEntries;
private SpiralAbyssView? selectedView;
private AdvancedCollectionView<SpiralAbyssView>? spiralAbyssEntries;
/// <summary>
/// 深渊记录
/// </summary>
public ObservableCollection<SpiralAbyssView>? SpiralAbyssEntries { get => spiralAbyssEntries; set => SetProperty(ref spiralAbyssEntries, value); }
/// <summary>
/// 选中的深渊信息
/// </summary>
public SpiralAbyssView? SelectedView { get => selectedView; set => SetProperty(ref selectedView, value); }
public AdvancedCollectionView<SpiralAbyssView>? SpiralAbyssEntries { get => spiralAbyssEntries; set => SetProperty(ref spiralAbyssEntries, value); }
public HutaoDatabaseViewModel HutaoDatabaseViewModel { get => hutaoDatabaseViewModel; }
@@ -61,7 +51,7 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
}
else
{
SelectedView = null;
SpiralAbyssEntries?.MoveCurrentTo(default);
}
}
@@ -85,7 +75,7 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
private async ValueTask UpdateSpiralAbyssCollectionAsync(UserAndUid userAndUid)
{
ObservableCollection<SpiralAbyssView>? collection = null;
ObservableCollection<SpiralAbyssView> collection;
try
{
using (await EnterCriticalSectionAsync().ConfigureAwait(false))
@@ -94,14 +84,15 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
.GetSpiralAbyssViewCollectionAsync(userAndUid)
.ConfigureAwait(false);
}
await taskContext.SwitchToMainThreadAsync();
SpiralAbyssEntries = new(collection, true);
SpiralAbyssEntries.MoveCurrentTo(SpiralAbyssEntries.SourceCollection.FirstOrDefault(s => s.Engaged));
}
catch (OperationCanceledException)
{
return;
}
await taskContext.SwitchToMainThreadAsync();
SpiralAbyssEntries = collection;
SelectedView = SpiralAbyssEntries?.FirstOrDefault(s => s.Engaged);
}
[Command("RefreshCommand")]
@@ -125,7 +116,7 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
}
await taskContext.SwitchToMainThreadAsync();
SelectedView = SpiralAbyssEntries.FirstOrDefault(s => s.Engaged);
SpiralAbyssEntries.MoveCurrentTo(SpiralAbyssEntries.SourceCollection.FirstOrDefault(s => s.Engaged));
}
}
}
@@ -158,24 +149,18 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
}
}
SimpleRecord? record = await spiralAbyssClient.GetPlayerRecordAsync(userAndUid).ConfigureAwait(false);
if (record is not null)
if (await spiralAbyssClient.GetPlayerRecordAsync(userAndUid).ConfigureAwait(false) is { } record)
{
Web.Response.Response response = await spiralAbyssClient.UploadRecordAsync(record).ConfigureAwait(false);
if (response is { ReturnCode: 0 })
{
if (response is ILocalizableResponse localizableResponse)
{
infoBarService.Success(localizableResponse.GetLocalizationMessage());
}
}
else
infoBarService.PrepareInfoBarAndShow(builder =>
{
if (response is ILocalizableResponse localizableResponse)
{
infoBarService.Warning(localizableResponse.GetLocalizationMessage());
}
builder
.SetSeverity(response is { ReturnCode: 0 } ? InfoBarSeverity.Success : InfoBarSeverity.Warning)
.SetMessage(localizableResponse.GetLocalizationMessage());
});
}
}
}

View File

@@ -5,14 +5,12 @@ using Snap.Hutao.Core.Abstraction;
using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Metadata.Tower;
using Snap.Hutao.UI.Xaml.Data;
namespace Snap.Hutao.ViewModel.SpiralAbyss;
/// <summary>
/// 深渊视图
/// </summary>
[HighQuality]
internal sealed class SpiralAbyssView : IEntityAccess<SpiralAbyssEntry?>,
internal sealed partial class SpiralAbyssView : IEntityAccess<SpiralAbyssEntry?>,
IAdvancedCollectionViewItem,
IMappingFrom<SpiralAbyssView, SpiralAbyssEntry, SpiralAbyssMetadataContext>,
IMappingFrom<SpiralAbyssView, SpiralAbyssEntry?, TowerSchedule, SpiralAbyssMetadataContext>
{

View File

@@ -15,7 +15,7 @@ using EntityUser = Snap.Hutao.Model.Entity.User;
namespace Snap.Hutao.ViewModel.User;
internal sealed class User : IEntityAccess<EntityUser>,
internal sealed partial class User : IEntityAccess<EntityUser>,
IMappingFrom<User, EntityUser, IServiceProvider>,
ISelectable,
IAdvancedCollectionViewItem
@@ -96,14 +96,6 @@ internal sealed class User : IEntityAccess<EntityUser>,
return new(user, provider);
}
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default,
};
}
public IDisposable SuppressCurrentUserGameRoleChangedMessage()
{
return new CurrentUserGameRoleChangedSuppression(this);

View File

@@ -11,6 +11,7 @@ namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
[ConstructorGenerated(ResolveHttpClient = true)]
[HttpClient(HttpClientConfiguration.Default)]
[PrimaryHttpMessageHandler(UseCookies = false)]
internal sealed partial class UserClientOversea : IUserClient
{
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;

View File

@@ -59,14 +59,6 @@ internal sealed partial class UserGameRole : ObservableObject, IAdvancedCollecti
return $"{Nickname} | {RegionName} | Lv.{Level}";
}
public object? GetPropertyValue(string name)
{
return name switch
{
_ => default,
};
}
[Command("RefreshProfilePictureCommand")]
private async Task RefreshProfilePictureAsync()
{