mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
2 Commits
fix/layout
...
feat/wikis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b86783493 | ||
|
|
e3adc2e595 |
@@ -14,8 +14,8 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -6,11 +6,8 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<XamlControlsResources/>
|
<XamlControlsResources/>
|
||||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.TokenizingTextBox/TokenizingTextBox.xaml"/>
|
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Loading.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Loading.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Image/CachedImage.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Image/CachedImage.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Segmented/Segmented.xaml"/>
|
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Segmented/SegmentedItem.xaml"/>
|
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Color.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/Color.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/ComboBox.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/ComboBox.xaml"/>
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using CommunityToolkit.WinUI;
|
|
||||||
using CommunityToolkit.WinUI.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
|
||||||
using Snap.Hutao.Control.Extension;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
|
||||||
|
|
||||||
[DependencyProperty("FilterCommand", typeof(ICommand))]
|
|
||||||
[DependencyProperty("FilterCommandParameter", typeof(object))]
|
|
||||||
[DependencyProperty("AvailableTokens", typeof(IReadOnlyDictionary<string, SearchToken>))]
|
|
||||||
internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
|
||||||
{
|
|
||||||
public AutoSuggestTokenBox()
|
|
||||||
{
|
|
||||||
DefaultStyleKey = typeof(TokenizingTextBox);
|
|
||||||
TextChanged += OnFilterSuggestionRequested;
|
|
||||||
QuerySubmitted += OnQuerySubmitted;
|
|
||||||
TokenItemAdding += OnTokenItemAdding;
|
|
||||||
TokenItemAdded += OnTokenItemModified;
|
|
||||||
TokenItemRemoved += OnTokenItemModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFilterSuggestionRequested(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(Text))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
|
||||||
{
|
|
||||||
sender.ItemsSource = AvailableTokens.Values.Where(q => q.Value.Contains(Text, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
// TODO: CornerRadius
|
|
||||||
// Popup? popup = this.FindDescendant("SuggestionsPopup") as Popup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnQuerySubmitted(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.ChosenSuggestion is not null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(args.TokenText))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Item = AvailableTokens.GetValueOrDefault(args.TokenText) ?? new SearchToken(SearchTokenKind.None, args.TokenText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTokenItemModified(TokenizingTextBox sender, object args)
|
|
||||||
{
|
|
||||||
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Windows.UI;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
|
||||||
|
|
||||||
internal sealed class SearchToken
|
|
||||||
{
|
|
||||||
public SearchToken(SearchTokenKind kind, string value, Uri? iconUri = null, Uri? sideIconUri = null, Color? quality = null)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
Kind = kind;
|
|
||||||
IconUri = iconUri;
|
|
||||||
SideIconUri = sideIconUri;
|
|
||||||
Quality = quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SearchTokenKind Kind { get; }
|
|
||||||
|
|
||||||
public string Value { get; set; } = default!;
|
|
||||||
|
|
||||||
public Uri? IconUri { get; }
|
|
||||||
|
|
||||||
public Uri? SideIconUri { get; }
|
|
||||||
|
|
||||||
public Color? Quality { get; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
|
||||||
|
|
||||||
internal enum SearchTokenKind
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
AssociationType,
|
|
||||||
Avatar,
|
|
||||||
BodyType,
|
|
||||||
ElementName,
|
|
||||||
FightProperty,
|
|
||||||
ItemQuality,
|
|
||||||
Weapon,
|
|
||||||
WeaponType,
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using CommunityToolkit.WinUI.Behaviors;
|
using CommunityToolkit.WinUI.Behaviors;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Snap.Hutao.Control.Extension;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Behavior;
|
namespace Snap.Hutao.Control.Behavior;
|
||||||
|
|
||||||
@@ -46,6 +45,10 @@ internal sealed partial class InvokeCommandOnLoadedBehavior : BehaviorBase<UIEle
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
executed = Command.TryExecute(CommandParameter);
|
if (Command is not null && Command.CanExecute(CommandParameter))
|
||||||
|
{
|
||||||
|
Command.Execute(CommandParameter);
|
||||||
|
executed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using CommunityToolkit.WinUI.Behaviors;
|
using CommunityToolkit.WinUI.Behaviors;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Snap.Hutao.Control.Extension;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Behavior;
|
namespace Snap.Hutao.Control.Behavior;
|
||||||
|
|
||||||
@@ -50,7 +49,10 @@ internal sealed partial class PeriodicInvokeCommandOrOnActualThemeChangedBehavio
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command.TryExecute(CommandParameter);
|
if (Command is not null && Command.CanExecute(CommandParameter))
|
||||||
|
{
|
||||||
|
Command.Execute(CommandParameter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask RunCoreAsync()
|
private async ValueTask RunCoreAsync()
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Extension;
|
|
||||||
|
|
||||||
internal static class CommandExtension
|
|
||||||
{
|
|
||||||
public static bool TryExecute(this ICommand? command, object? parameter = null)
|
|
||||||
{
|
|
||||||
if (command is not null && command.CanExecute(parameter))
|
|
||||||
{
|
|
||||||
command.Execute(parameter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Helper;
|
|
||||||
|
|
||||||
[SuppressMessage("", "SH001")]
|
|
||||||
[DependencyProperty("VisibilityObject", typeof(object), null, nameof(OnVisibilityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
|
|
||||||
[DependencyProperty("OpacityObject", typeof(object), null, nameof(OnOpacityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
|
|
||||||
public sealed partial class UIElementHelper
|
|
||||||
{
|
|
||||||
private static void OnVisibilityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
UIElement element = (UIElement)dp;
|
|
||||||
element.Visibility = e.NewValue is null ? Visibility.Collapsed : Visibility.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnOpacityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
UIElement element = (UIElement)dp;
|
|
||||||
element.Opacity = e.NewValue is null ? 0D : 1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
x:Class="Snap.Hutao.Control.Panel.PanelSelector"
|
x:Class="Snap.Hutao.Control.Panel.PanelSelector"
|
||||||
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:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
Style="{StaticResource DefaultSegmentedStyle}"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<shcs:SegmentedItem
|
<cwc:SegmentedItem
|
||||||
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentBulletedList}}"
|
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentBulletedList}}"
|
||||||
Tag="List"
|
Tag="List"
|
||||||
ToolTipService.ToolTip="{shcm:ResourceString Name=ControlPanelPanelSelectorDropdownListName}"/>
|
ToolTipService.ToolTip="{shcm:ResourceString Name=ControlPanelPanelSelectorDropdownListName}"/>
|
||||||
<shcs:SegmentedItem
|
<cwc:SegmentedItem
|
||||||
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentGridView}}"
|
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentGridView}}"
|
||||||
Tag="Grid"
|
Tag="Grid"
|
||||||
ToolTipService.ToolTip="{shcm:ResourceString Name=ControlPanelPanelSelectorDropdownGridName}"/>
|
ToolTipService.ToolTip="{shcm:ResourceString Name=ControlPanelPanelSelectorDropdownGridName}"/>
|
||||||
|
|
||||||
</shcs:Segmented>
|
</cwc:Segmented>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Controls;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Snap.Hutao.Control.Segmented;
|
|
||||||
using Snap.Hutao.Core.Setting;
|
using Snap.Hutao.Core.Setting;
|
||||||
using System.Collections.Frozen;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Panel;
|
namespace Snap.Hutao.Control.Panel;
|
||||||
|
|
||||||
@@ -15,16 +14,16 @@ namespace Snap.Hutao.Control.Panel;
|
|||||||
[DependencyProperty("Current", typeof(string), List)]
|
[DependencyProperty("Current", typeof(string), List)]
|
||||||
[DependencyProperty("LocalSettingKeySuffixForCurrent", typeof(string))]
|
[DependencyProperty("LocalSettingKeySuffixForCurrent", typeof(string))]
|
||||||
[DependencyProperty("LocalSettingKeyExtraForCurrent", typeof(string), "")]
|
[DependencyProperty("LocalSettingKeyExtraForCurrent", typeof(string), "")]
|
||||||
internal sealed partial class PanelSelector : Segmented.Segmented
|
internal sealed partial class PanelSelector : Segmented
|
||||||
{
|
{
|
||||||
public const string List = nameof(List);
|
public const string List = nameof(List);
|
||||||
public const string Grid = nameof(Grid);
|
public const string Grid = nameof(Grid);
|
||||||
|
|
||||||
private static readonly FrozenDictionary<int, string> IndexTypeMap = FrozenDictionary.ToFrozenDictionary(
|
private static readonly Dictionary<int, string> IndexTypeMap = new()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(0, List),
|
[0] = List,
|
||||||
KeyValuePair.Create(1, Grid),
|
[1] = Grid,
|
||||||
]);
|
};
|
||||||
|
|
||||||
private readonly RoutedEventHandler loadedEventHandler;
|
private readonly RoutedEventHandler loadedEventHandler;
|
||||||
private readonly RoutedEventHandler unloadedEventHandler;
|
private readonly RoutedEventHandler unloadedEventHandler;
|
||||||
|
|||||||
@@ -41,12 +41,14 @@ internal class ScopedPage : Page
|
|||||||
/// 应当在 InitializeComponent() 前调用
|
/// 应当在 InitializeComponent() 前调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TViewModel">视图模型类型</typeparam>
|
/// <typeparam name="TViewModel">视图模型类型</typeparam>
|
||||||
protected void InitializeWith<TViewModel>()
|
protected TViewModel InitializeWith<TViewModel>()
|
||||||
where TViewModel : class, IViewModel
|
where TViewModel : class, IViewModel
|
||||||
{
|
{
|
||||||
IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService<TViewModel>();
|
IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService<TViewModel>();
|
||||||
viewModel.CancellationToken = viewCancellationTokenSource.Token;
|
viewModel.CancellationToken = viewCancellationTokenSource.Token;
|
||||||
DataContext = viewModel;
|
DataContext = viewModel;
|
||||||
|
|
||||||
|
return (TViewModel)viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using System.Data;
|
|
||||||
using Windows.Foundation;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Segmented;
|
|
||||||
|
|
||||||
[DependencyProperty("Spacing", typeof(double), default(double), nameof(OnSpacingChanged))]
|
|
||||||
internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel
|
|
||||||
{
|
|
||||||
private double maxItemWidth;
|
|
||||||
private double maxItemHeight;
|
|
||||||
private int visibleItemsCount;
|
|
||||||
|
|
||||||
public EqualPanel()
|
|
||||||
{
|
|
||||||
RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
|
||||||
{
|
|
||||||
maxItemWidth = 0;
|
|
||||||
maxItemHeight = 0;
|
|
||||||
|
|
||||||
IEnumerable<UIElement> elements = Children.Where(static e => e.Visibility == Visibility.Visible);
|
|
||||||
visibleItemsCount = elements.Count();
|
|
||||||
|
|
||||||
foreach (UIElement child in elements)
|
|
||||||
{
|
|
||||||
child.Measure(availableSize);
|
|
||||||
maxItemWidth = Math.Max(maxItemWidth, child.DesiredSize.Width);
|
|
||||||
maxItemHeight = Math.Max(maxItemHeight, child.DesiredSize.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visibleItemsCount > 0)
|
|
||||||
{
|
|
||||||
// Return equal widths based on the widest item
|
|
||||||
// In very specific edge cases the AvailableWidth might be infinite resulting in a crash.
|
|
||||||
if (HorizontalAlignment != HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width))
|
|
||||||
{
|
|
||||||
return new Size((maxItemWidth * visibleItemsCount) + (Spacing * (visibleItemsCount - 1)), maxItemHeight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Equal columns based on the available width, adjust for spacing
|
|
||||||
double totalWidth = availableSize.Width - (Spacing * (visibleItemsCount - 1));
|
|
||||||
maxItemWidth = totalWidth / visibleItemsCount;
|
|
||||||
return new Size(availableSize.Width, maxItemHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Size(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
|
||||||
{
|
|
||||||
double x = 0;
|
|
||||||
|
|
||||||
// Check if there's more (little) width available - if so, set max item width to the maximum possible as we have an almost perfect height.
|
|
||||||
if (finalSize.Width > (visibleItemsCount * maxItemWidth) + (Spacing * (visibleItemsCount - 1)))
|
|
||||||
{
|
|
||||||
maxItemWidth = (finalSize.Width - (Spacing * (visibleItemsCount - 1))) / visibleItemsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<UIElement> elements = Children.Where(static e => e.Visibility == Visibility.Visible);
|
|
||||||
foreach (UIElement child in elements)
|
|
||||||
{
|
|
||||||
child.Arrange(new Rect(x, 0, maxItemWidth, maxItemHeight));
|
|
||||||
x += maxItemWidth + Spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
EqualPanel panel = (EqualPanel)d;
|
|
||||||
panel.InvalidateMeasure();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
|
|
||||||
{
|
|
||||||
InvalidateMeasure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Input;
|
|
||||||
using Windows.System;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Segmented;
|
|
||||||
|
|
||||||
internal partial class Segmented : ListViewBase
|
|
||||||
{
|
|
||||||
private int correctSelectedIndex = -1;
|
|
||||||
|
|
||||||
public Segmented()
|
|
||||||
{
|
|
||||||
DefaultStyleKey = typeof(Segmented);
|
|
||||||
|
|
||||||
RegisterPropertyChangedCallback(SelectedIndexProperty, OnSelectedIndexChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override DependencyObject GetContainerForItemOverride() => new SegmentedItem();
|
|
||||||
|
|
||||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
|
||||||
{
|
|
||||||
return item is SegmentedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnApplyTemplate()
|
|
||||||
{
|
|
||||||
base.OnApplyTemplate();
|
|
||||||
if (!IsLoaded)
|
|
||||||
{
|
|
||||||
SelectedIndex = correctSelectedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreviewKeyDown -= OnPreviewKeyDown;
|
|
||||||
PreviewKeyDown += OnPreviewKeyDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
|
||||||
{
|
|
||||||
base.PrepareContainerForItemOverride(element, item);
|
|
||||||
if (element is SegmentedItem segmentedItem)
|
|
||||||
{
|
|
||||||
segmentedItem.Loaded += OnLoaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnItemsChanged(object e)
|
|
||||||
{
|
|
||||||
base.OnItemsChanged(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
switch (e.Key)
|
|
||||||
{
|
|
||||||
case VirtualKey.Left:
|
|
||||||
e.Handled = MoveFocus(true);
|
|
||||||
break;
|
|
||||||
case VirtualKey.Right:
|
|
||||||
e.Handled = MoveFocus(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is SegmentedItem segmentedItem)
|
|
||||||
{
|
|
||||||
segmentedItem.Loaded -= OnLoaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool MoveFocus(bool reverse)
|
|
||||||
{
|
|
||||||
SegmentedItem? currentContainerItem = GetCurrentContainerItem();
|
|
||||||
|
|
||||||
if (currentContainerItem is null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int previousIndex = Items.IndexOf(ItemFromContainer(currentContainerItem));
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
{
|
|
||||||
if (previousIndex > 0 && ContainerFromIndex(previousIndex - 1) is SegmentedItem newItem)
|
|
||||||
{
|
|
||||||
newItem.Focus(FocusState.Keyboard);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (previousIndex < Items.Count - 1 && ContainerFromIndex(previousIndex + 1) is SegmentedItem newItem)
|
|
||||||
{
|
|
||||||
newItem.Focus(FocusState.Keyboard);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SegmentedItem? GetCurrentContainerItem()
|
|
||||||
{
|
|
||||||
if (XamlRoot is not null)
|
|
||||||
{
|
|
||||||
return (SegmentedItem)FocusManager.GetFocusedElement(XamlRoot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (SegmentedItem)FocusManager.GetFocusedElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSelectedIndexChanged(DependencyObject sender, DependencyProperty dp)
|
|
||||||
{
|
|
||||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/8257
|
|
||||||
if (correctSelectedIndex == -1 && SelectedIndex > -1)
|
|
||||||
{
|
|
||||||
correctSelectedIndex = SelectedIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
<ResourceDictionary
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:cw="using:CommunityToolkit.WinUI"
|
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
|
||||||
|
|
||||||
<ResourceDictionary.MergedDictionaries>
|
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Segmented/SegmentedItem.xaml"/>
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
|
||||||
<ResourceDictionary.ThemeDictionaries>
|
|
||||||
<ResourceDictionary x:Key="Default">
|
|
||||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="ControlStrokeColorDefaultBrush"/>
|
|
||||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
|
||||||
</ResourceDictionary>
|
|
||||||
<ResourceDictionary x:Key="Light">
|
|
||||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="ControlStrokeColorDefaultBrush"/>
|
|
||||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
|
||||||
</ResourceDictionary>
|
|
||||||
<ResourceDictionary x:Key="HighContrast">
|
|
||||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="SystemColorButtonFaceColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="SystemColorHighlightColorBrush"/>
|
|
||||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ResourceDictionary.ThemeDictionaries>
|
|
||||||
|
|
||||||
<x:Double x:Key="SegmentedItemSpacing">1</x:Double>
|
|
||||||
<x:Double x:Key="ButtonItemSpacing">2</x:Double>
|
|
||||||
|
|
||||||
<Style BasedOn="{StaticResource DefaultSegmentedStyle}" TargetType="shcs:Segmented"/>
|
|
||||||
|
|
||||||
<Style x:Key="DefaultSegmentedStyle" TargetType="shcs:Segmented">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
|
|
||||||
<Setter Property="Background" Value="{ThemeResource SegmentedBackground}"/>
|
|
||||||
<Setter Property="BorderBrush" Value="{ThemeResource SegmentedBorderBrush}"/>
|
|
||||||
<Setter Property="BorderThickness" Value="{ThemeResource SegmentedBorderThickness}"/>
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
|
||||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
|
||||||
<Setter Property="SelectionMode" Value="Single"/>
|
|
||||||
<Setter Property="IsItemClickEnabled" Value="False"/>
|
|
||||||
<win:Setter Property="SingleSelectionFollowsFocus" Value="False"/>
|
|
||||||
<Setter Property="IsTabStop" Value="False"/>
|
|
||||||
<Setter Property="TabNavigation" Value="Once"/>
|
|
||||||
<Setter Property="ItemsPanel">
|
|
||||||
<Setter.Value>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<shcs:EqualPanel
|
|
||||||
HorizontalAlignment="{Binding (cw:FrameworkElementExtensions.Ancestor).HorizontalAlignment, RelativeSource={RelativeSource Self}}"
|
|
||||||
cw:FrameworkElementExtensions.AncestorType="shcs:Segmented"
|
|
||||||
Spacing="{ThemeResource SegmentedItemSpacing}"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="shcs:Segmented">
|
|
||||||
<Grid>
|
|
||||||
<Border
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
CornerRadius="{TemplateBinding CornerRadius}"/>
|
|
||||||
<ItemsPresenter Margin="{TemplateBinding Padding}"/>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style
|
|
||||||
x:Key="PivotSegmentedStyle"
|
|
||||||
BasedOn="{StaticResource DefaultSegmentedStyle}"
|
|
||||||
TargetType="shcs:Segmented">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
|
||||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
|
||||||
<Setter Property="BorderThickness" Value="0"/>
|
|
||||||
<Setter Property="Padding" Value="0"/>
|
|
||||||
<Setter Property="ItemContainerStyle" Value="{StaticResource PivotSegmentedItemStyle}"/>
|
|
||||||
<Setter Property="ItemsPanel">
|
|
||||||
<Setter.Value>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="{ThemeResource SegmentedItemSpacing}"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style
|
|
||||||
x:Key="ButtonSegmentedStyle"
|
|
||||||
BasedOn="{StaticResource DefaultSegmentedStyle}"
|
|
||||||
TargetType="shcs:Segmented">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
|
||||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
|
||||||
<Setter Property="BorderThickness" Value="0"/>
|
|
||||||
<Setter Property="Padding" Value="0"/>
|
|
||||||
<Setter Property="ItemContainerStyle" Value="{StaticResource ButtonSegmentedItemStyle}"/>
|
|
||||||
<Setter Property="ItemsPanel">
|
|
||||||
<Setter.Value>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="{ThemeResource ButtonItemSpacing}"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Segmented;
|
|
||||||
|
|
||||||
[DependencyProperty("Icon", typeof(IconElement), null, nameof(OnIconPropertyChanged))]
|
|
||||||
internal partial class SegmentedItem : ListViewItem
|
|
||||||
{
|
|
||||||
private const string IconLeftState = "IconLeft";
|
|
||||||
private const string IconOnlyState = "IconOnly";
|
|
||||||
private const string ContentOnlyState = "ContentOnly";
|
|
||||||
|
|
||||||
public SegmentedItem()
|
|
||||||
{
|
|
||||||
DefaultStyleKey = typeof(SegmentedItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnApplyTemplate()
|
|
||||||
{
|
|
||||||
base.OnApplyTemplate();
|
|
||||||
OnIconChanged();
|
|
||||||
ContentChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnContentChanged(object oldContent, object newContent)
|
|
||||||
{
|
|
||||||
base.OnContentChanged(oldContent, newContent);
|
|
||||||
ContentChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnIconPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
((SegmentedItem)d).OnIconChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ContentChanged()
|
|
||||||
{
|
|
||||||
if (Content is not null)
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, IconLeftState, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, IconOnlyState, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnIconChanged()
|
|
||||||
{
|
|
||||||
if (Icon is not null)
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, IconLeftState, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, ContentOnlyState, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,875 +0,0 @@
|
|||||||
<ResourceDictionary
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
|
||||||
|
|
||||||
<ResourceDictionary.ThemeDictionaries>
|
|
||||||
<ResourceDictionary x:Key="Default">
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundSelected" ResourceKey="ControlFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPressed" ResourceKey="SubtleFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundDisabled" ResourceKey="ControlFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- BorderBrush -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrush" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushSelected" ResourceKey="ControlElevationBorderBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPressed" ResourceKey="SubtleFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushDisabled" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="SegmentedItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPointerOver" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundSelected" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPressed" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="SegmentedPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundDisabled" ResourceKey="AccentFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<Thickness x:Key="SegmentedItemBorderThickness">1</Thickness>
|
|
||||||
<x:Double x:Key="SegmentedItemDisabledOpacity">0.55</x:Double>
|
|
||||||
|
|
||||||
<!-- PillSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="PivotItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPointerOver" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundSelected" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPressed" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="PivotItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPointerOver" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPressed" ResourceKey="TextFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundSelected" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="PivotItemPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundDisabled" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
|
|
||||||
<!-- ButtonSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="ButtonItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPressed" ResourceKey="SubtleFillColorTertiary"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelected" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="ButtonItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPointerOver" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPressed" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelected" ResourceKey="TextOnAccentFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPointerOver" ResourceKey="TextOnAccentFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPressed" ResourceKey="TextOnAccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
</ResourceDictionary>
|
|
||||||
<ResourceDictionary x:Key="Light">
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundSelected" ResourceKey="ControlFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPressed" ResourceKey="SubtleFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundDisabled" ResourceKey="ControlFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- BorderBrush -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrush" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushSelected" ResourceKey="ControlElevationBorderBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPressed" ResourceKey="SubtleFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushDisabled" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="SegmentedItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPointerOver" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundSelected" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPressed" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="SegmentedPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundDisabled" ResourceKey="AccentFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<Thickness x:Key="SegmentedItemBorderThickness">1</Thickness>
|
|
||||||
<x:Double x:Key="SegmentedItemDisabledOpacity">0.55</x:Double>
|
|
||||||
|
|
||||||
<!-- PillSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="PivotItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPointerOver" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundSelected" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPressed" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="PivotItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPointerOver" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPressed" ResourceKey="TextFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundSelected" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="PivotItemPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundDisabled" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
|
|
||||||
<!-- ButtonSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="ButtonItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPressed" ResourceKey="SubtleFillColorTertiary"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelected" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="ButtonItemForeground" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPointerOver" ResourceKey="TextFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPressed" ResourceKey="TextFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelected" ResourceKey="TextOnAccentFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPointerOver" ResourceKey="TextOnAccentFillColorPrimaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPressed" ResourceKey="TextOnAccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundDisabled" ResourceKey="TextFillColorDisabledBrush"/>
|
|
||||||
</ResourceDictionary>
|
|
||||||
|
|
||||||
<ResourceDictionary x:Key="HighContrast">
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBackground" ResourceKey="SystemColorButtonFaceColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPointerOver" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundSelected" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundPressed" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush"/>
|
|
||||||
|
|
||||||
<!-- BorderBrush -->
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrush" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPointerOver" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushSelected" ResourceKey="ControlElevationBorderBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushPressed" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemBorderBrushDisabled" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="SegmentedItemForeground" ResourceKey="SystemColorButtonTextColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPointerOver" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundSelected" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundPressed" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="SegmentedItemForegroundDisabled" ResourceKey="SystemColorGrayTextColor"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="SegmentedPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="SegmentedPillBackgroundDisabled" ResourceKey="AccentFillColorDisabledBrush"/>
|
|
||||||
|
|
||||||
<Thickness x:Key="SegmentedItemBorderThickness">1</Thickness>
|
|
||||||
<x:Double x:Key="SegmentedItemDisabledOpacity">0.55</x:Double>
|
|
||||||
|
|
||||||
<!-- PillSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="PivotItemBackground" ResourceKey="SystemColorButtonFaceColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPointerOver" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundSelected" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundPressed" ResourceKey="SystemColorHighlightColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemBackgroundDisabled" ResourceKey="SystemColorButtonTextColor"/>
|
|
||||||
|
|
||||||
<!-- Pill -->
|
|
||||||
<StaticResource x:Key="PivotItemPillBackground" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPointerOver" ResourceKey="AccentFillColorSecondaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundPressed" ResourceKey="AccentFillColorTertiaryBrush"/>
|
|
||||||
<StaticResource x:Key="PivotItemPillBackgroundDisabled" ResourceKey="AccentFillColorDefaultBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="PivotItemForeground" ResourceKey="SystemColorButtonTextColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPointerOver" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundSelected" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundPressed" ResourceKey="SystemColorHighlightTextColor"/>
|
|
||||||
<StaticResource x:Key="PivotItemForegroundDisabled" ResourceKey="SystemColorGrayTextColor"/>
|
|
||||||
|
|
||||||
<!-- ButtonSegmentedStyle -->
|
|
||||||
<!-- Background -->
|
|
||||||
<StaticResource x:Key="ButtonItemBackground" ResourceKey="ControlFillColorTransparentBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundPressed" ResourceKey="SystemColorHighlightTextColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelected" ResourceKey="SystemControlHighlightAccentBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPointerOver" ResourceKey="SystemColorButtonTextColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundSelectedPressed" ResourceKey="SystemColorHighlightTextColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush"/>
|
|
||||||
|
|
||||||
<!-- Foreground -->
|
|
||||||
<StaticResource x:Key="ButtonItemForeground" ResourceKey="SystemColorButtonTextColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelected" ResourceKey="SystemControlHighlightAltChromeWhiteBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPointerOver" ResourceKey="SystemColorButtonFaceColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundSelectedPressed" ResourceKey="SystemColorHighlightColorBrush"/>
|
|
||||||
<StaticResource x:Key="ButtonItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush"/>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ResourceDictionary.ThemeDictionaries>
|
|
||||||
|
|
||||||
<x:String x:Key="SegmentedItemScaleAnimationDuration">00:00:00.167</x:String>
|
|
||||||
|
|
||||||
<Style BasedOn="{StaticResource DefaultSegmentedItemStyle}" TargetType="shcs:SegmentedItem"/>
|
|
||||||
|
|
||||||
<shcs:SegmentedMarginConverter
|
|
||||||
x:Name="MarginConverter"
|
|
||||||
LeftItemMargin="{StaticResource LeftItemHoverMargin}"
|
|
||||||
MiddleItemMargin="{StaticResource MiddleItemHoverMargin}"
|
|
||||||
RightItemMargin="{StaticResource RightItemHoverMargin}"/>
|
|
||||||
|
|
||||||
<Thickness x:Key="LeftItemHoverMargin">3, 3, 1, 3</Thickness>
|
|
||||||
<Thickness x:Key="MiddleItemHoverMargin">1, 3, 1, 3</Thickness>
|
|
||||||
<Thickness x:Key="RightItemHoverMargin">1, 3, 3, 3</Thickness>
|
|
||||||
<Thickness x:Key="ButtonItemPadding">11</Thickness>
|
|
||||||
<Style x:Key="DefaultSegmentedItemStyle" TargetType="shcs:SegmentedItem">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
|
||||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
|
|
||||||
<Setter Property="Background" Value="{ThemeResource SegmentedItemBackground}"/>
|
|
||||||
<Setter Property="BorderBrush" Value="{ThemeResource SegmentedItemBorderBrush}"/>
|
|
||||||
<Setter Property="BorderThickness" Value="{ThemeResource SegmentedItemBorderThickness}"/>
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource SegmentedItemForeground}"/>
|
|
||||||
<Setter Property="FontWeight" Value="Normal"/>
|
|
||||||
<Setter Property="TabNavigation" Value="Local"/>
|
|
||||||
<Setter Property="UseSystemFocusVisuals" Value="True"/>
|
|
||||||
<Setter Property="FocusVisualMargin" Value="-3"/>
|
|
||||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge"/>
|
|
||||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
|
|
||||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="shcs:SegmentedItem">
|
|
||||||
<Grid
|
|
||||||
x:Name="PART_Root"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
Control.IsTemplateFocusTarget="True"
|
|
||||||
CornerRadius="{TemplateBinding CornerRadius}">
|
|
||||||
<win:Grid.BackgroundTransition>
|
|
||||||
<win:BrushTransition Duration="0:0:0.083"/>
|
|
||||||
</win:Grid.BackgroundTransition>
|
|
||||||
|
|
||||||
<Border
|
|
||||||
x:Name="PART_Hover"
|
|
||||||
Margin="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource MarginConverter}}"
|
|
||||||
Background="Transparent"
|
|
||||||
CornerRadius="2"
|
|
||||||
RenderTransformOrigin="0.5, 0.5">
|
|
||||||
<win:Border.BackgroundTransition>
|
|
||||||
<win:BrushTransition Duration="0:0:0.083"/>
|
|
||||||
</win:Border.BackgroundTransition>
|
|
||||||
<Border.RenderTransform>
|
|
||||||
<CompositeTransform/>
|
|
||||||
</Border.RenderTransform>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Content -->
|
|
||||||
<Grid
|
|
||||||
x:Name="ContentHolder"
|
|
||||||
Margin="11,0,11,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
ColumnSpacing="8">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Viewbox
|
|
||||||
x:Name="PART_IconBox"
|
|
||||||
Width="16"
|
|
||||||
Margin="0,7,0,7"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_IconPresenter"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
Content="{TemplateBinding Icon}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</Viewbox>
|
|
||||||
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_ContentPresenter"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,5,0,6"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
win:OpticalMarginAlignment="TrimSideBearings"
|
|
||||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
|
||||||
Content="{TemplateBinding Content}"
|
|
||||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
|
||||||
FontWeight="{TemplateBinding FontWeight}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
<Rectangle
|
|
||||||
x:Name="PART_Pill"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="4"
|
|
||||||
Height="3"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Fill="{ThemeResource SegmentedPillBackground}"
|
|
||||||
Opacity="0"
|
|
||||||
RadiusX="0.5"
|
|
||||||
RadiusY="1"
|
|
||||||
RenderTransformOrigin="0.5, 0.5">
|
|
||||||
<Rectangle.RenderTransform>
|
|
||||||
<CompositeTransform x:Name="PillTransform" ScaleX="1"/>
|
|
||||||
</Rectangle.RenderTransform>
|
|
||||||
</Rectangle>
|
|
||||||
</Grid>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="SegmentedIconPositionStates">
|
|
||||||
<VisualState x:Name="IconOnLeft"/>
|
|
||||||
<VisualState x:Name="IconOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_ContentPresenter.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="PART_Pill.(Grid.Column)" Value="0"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="ContentOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_IconBox.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal"/>
|
|
||||||
<VisualState x:Name="PointerOver">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Hover" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBackgroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Pressed">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Hover" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="0.96"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Hover" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="0.96"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Hover" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBackgroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Selected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="4"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedPillBackground}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="BorderBrush">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBorderBrushSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PointerOverSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="4"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedPillBackgroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="BorderBrush">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBorderBrushSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PressedSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="2"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Fill">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedPillBackgroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="BorderBrush">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemBorderBrushSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SegmentedItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
<VisualStateGroup x:Name="DisabledStates">
|
|
||||||
<VisualState x:Name="Enabled"/>
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation
|
|
||||||
Storyboard.TargetName="PART_Root"
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
To="{ThemeResource SegmentedItemDisabledOpacity}"
|
|
||||||
Duration="0:0:0.083"/>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style
|
|
||||||
x:Key="PivotSegmentedItemStyle"
|
|
||||||
BasedOn="{StaticResource DefaultSegmentedItemStyle}"
|
|
||||||
TargetType="shcs:SegmentedItem">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Background" Value="{ThemeResource PivotItemBackground}"/>
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource PivotItemForeground}"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="shcs:SegmentedItem">
|
|
||||||
<Grid
|
|
||||||
x:Name="PART_Root"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
Control.IsTemplateFocusTarget="True"
|
|
||||||
CornerRadius="{TemplateBinding CornerRadius}">
|
|
||||||
<!-- Content -->
|
|
||||||
<Grid
|
|
||||||
x:Name="ContentHolder"
|
|
||||||
Margin="12,0,12,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
ColumnSpacing="8">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Viewbox
|
|
||||||
x:Name="PART_IconBox"
|
|
||||||
Width="16"
|
|
||||||
Margin="0,11,0,11"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_IconPresenter"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
Content="{TemplateBinding Icon}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</Viewbox>
|
|
||||||
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_ContentPresenter"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,9,0,10"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
win:OpticalMarginAlignment="TrimSideBearings"
|
|
||||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
|
||||||
Content="{TemplateBinding Content}"
|
|
||||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
|
||||||
FontWeight="{TemplateBinding FontWeight}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
<Rectangle
|
|
||||||
x:Name="PART_Pill"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="4"
|
|
||||||
Height="3"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Fill="{ThemeResource PivotItemPillBackground}"
|
|
||||||
Opacity="0"
|
|
||||||
RadiusX="0.5"
|
|
||||||
RadiusY="1"
|
|
||||||
RenderTransformOrigin="0.5, 0.5">
|
|
||||||
<Rectangle.RenderTransform>
|
|
||||||
<CompositeTransform x:Name="PillTransform" ScaleX="1"/>
|
|
||||||
</Rectangle.RenderTransform>
|
|
||||||
</Rectangle>
|
|
||||||
</Grid>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="SegmentedIconPositionStates">
|
|
||||||
<VisualState x:Name="IconOnLeft"/>
|
|
||||||
<VisualState x:Name="IconOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_ContentPresenter.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="PART_Pill.(Grid.Column)" Value="0"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="ContentOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_IconBox.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal"/>
|
|
||||||
<VisualState x:Name="PointerOver">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemBackgroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Pressed">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemBackgroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Selected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="4"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PointerOverSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="4"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PressedSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="2"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Pill" Storyboard.TargetProperty="Opacity">
|
|
||||||
<SplineDoubleKeyFrame
|
|
||||||
KeySpline="0,0,0,1"
|
|
||||||
KeyTime="{ThemeResource SegmentedItemScaleAnimationDuration}"
|
|
||||||
Value="1"/>
|
|
||||||
</DoubleAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
<VisualStateGroup x:Name="DisabledStates">
|
|
||||||
<VisualState x:Name="Enabled"/>
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation
|
|
||||||
Storyboard.TargetName="PART_Root"
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
To="{ThemeResource SegmentedItemDisabledOpacity}"
|
|
||||||
Duration="0:0:0.083"/>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style
|
|
||||||
x:Key="ButtonSegmentedItemStyle"
|
|
||||||
BasedOn="{StaticResource DefaultSegmentedItemStyle}"
|
|
||||||
TargetType="shcs:SegmentedItem">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Background" Value="{ThemeResource ButtonItemBackground}"/>
|
|
||||||
<Setter Property="Foreground" Value="{ThemeResource ButtonItemForeground}"/>
|
|
||||||
<Setter Property="Padding" Value="{ThemeResource ButtonItemPadding}"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="shcs:SegmentedItem">
|
|
||||||
<Grid
|
|
||||||
x:Name="PART_Root"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
|
||||||
Control.IsTemplateFocusTarget="True"
|
|
||||||
CornerRadius="{TemplateBinding CornerRadius}">
|
|
||||||
<win:Grid.BackgroundTransition>
|
|
||||||
<win:BrushTransition Duration="0:0:0.083"/>
|
|
||||||
</win:Grid.BackgroundTransition>
|
|
||||||
|
|
||||||
<!-- Content -->
|
|
||||||
<Grid
|
|
||||||
x:Name="ContentHolder"
|
|
||||||
Margin="{TemplateBinding Padding}"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
ColumnSpacing="8">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Viewbox
|
|
||||||
x:Name="PART_IconBox"
|
|
||||||
Width="16"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_IconPresenter"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
Content="{TemplateBinding Icon}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</Viewbox>
|
|
||||||
|
|
||||||
<ContentPresenter
|
|
||||||
x:Name="PART_ContentPresenter"
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
win:HighContrastAdjustment="None"
|
|
||||||
win:OpticalMarginAlignment="TrimSideBearings"
|
|
||||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
|
||||||
Content="{TemplateBinding Content}"
|
|
||||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
|
||||||
FontWeight="{TemplateBinding FontWeight}"
|
|
||||||
Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</Grid>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="SegmentedIconPositionStates">
|
|
||||||
<VisualState x:Name="IconOnLeft"/>
|
|
||||||
<VisualState x:Name="IconOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_ContentPresenter.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="ContentOnly">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_IconBox.Visibility" Value="Collapsed"/>
|
|
||||||
<Setter Target="ContentHolder.ColumnSpacing" Value="0"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal"/>
|
|
||||||
<VisualState x:Name="PointerOver">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemBackgroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Pressed">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemBackgroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Selected">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemBackgroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelected}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PointerOverSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemBackgroundSelectedPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelectedPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelectedPointerOver}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PressedSelected">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="Background">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemBackgroundSelectedPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelectedPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_IconPresenter" Storyboard.TargetProperty="Foreground">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonItemForegroundSelectedPressed}"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
<VisualStateGroup x:Name="DisabledStates">
|
|
||||||
<VisualState x:Name="Enabled"/>
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation
|
|
||||||
Storyboard.TargetName="PART_Root"
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
To="{ThemeResource SegmentedItemDisabledOpacity}"
|
|
||||||
Duration="0:0:0.083"/>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
</ResourceDictionary>
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Data;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Segmented;
|
|
||||||
|
|
||||||
[DependencyProperty("LeftItemMargin", typeof(Thickness))]
|
|
||||||
[DependencyProperty("MiddleItemMargin", typeof(Thickness))]
|
|
||||||
[DependencyProperty("RightItemMargin", typeof(Thickness))]
|
|
||||||
internal partial class SegmentedMarginConverter : DependencyObject, IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
SegmentedItem segmentedItem = (SegmentedItem)value;
|
|
||||||
ItemsControl listView = ItemsControl.ItemsControlFromItemContainer(segmentedItem);
|
|
||||||
|
|
||||||
int index = listView.IndexFromContainer(segmentedItem);
|
|
||||||
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
return LeftItemMargin;
|
|
||||||
}
|
|
||||||
else if (index == listView.Items.Count - 1)
|
|
||||||
{
|
|
||||||
return RightItemMargin;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MiddleItemMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,9 +17,6 @@
|
|||||||
<ItemsPanelTemplate x:Key="HorizontalStackPanelSpacing2Template">
|
<ItemsPanelTemplate x:Key="HorizontalStackPanelSpacing2Template">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="2"/>
|
<StackPanel Orientation="Horizontal" Spacing="2"/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
<ItemsPanelTemplate x:Key="HorizontalStackPanelSpacing4Template">
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="4"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
<ItemsPanelTemplate x:Key="StackPanelSpacing4Template">
|
<ItemsPanelTemplate x:Key="StackPanelSpacing4Template">
|
||||||
<StackPanel Spacing="4"/>
|
<StackPanel Spacing="4"/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
|
|||||||
@@ -11,6 +11,4 @@ internal static class KnownColors
|
|||||||
public static readonly Color Orange = StructMarshal.Color(0xFFBC6932);
|
public static readonly Color Orange = StructMarshal.Color(0xFFBC6932);
|
||||||
public static readonly Color Purple = StructMarshal.Color(0xFFA156E0);
|
public static readonly Color Purple = StructMarshal.Color(0xFFA156E0);
|
||||||
public static readonly Color Blue = StructMarshal.Color(0xFF5180CB);
|
public static readonly Color Blue = StructMarshal.Color(0xFF5180CB);
|
||||||
public static readonly Color Green = StructMarshal.Color(0xFF2A8F72);
|
|
||||||
public static readonly Color White = StructMarshal.Color(0xFF72778B);
|
|
||||||
}
|
}
|
||||||
@@ -26,12 +26,12 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
|||||||
{
|
{
|
||||||
private const string CacheFolderName = nameof(ImageCache);
|
private const string CacheFolderName = nameof(ImageCache);
|
||||||
|
|
||||||
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = FrozenDictionary.ToFrozenDictionary(
|
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = new Dictionary<int, TimeSpan>()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(0, TimeSpan.FromSeconds(4)),
|
[0] = TimeSpan.FromSeconds(4),
|
||||||
KeyValuePair.Create(1, TimeSpan.FromSeconds(16)),
|
[1] = TimeSpan.FromSeconds(16),
|
||||||
KeyValuePair.Create(2, TimeSpan.FromSeconds(64)),
|
[2] = TimeSpan.FromSeconds(64),
|
||||||
]);
|
}.ToFrozenDictionary();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ internal static partial class IocHttpClientConfiguration
|
|||||||
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
|
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
|
||||||
{
|
{
|
||||||
HttpClientHandler clientHandler = (HttpClientHandler)handler;
|
HttpClientHandler clientHandler = (HttpClientHandler)handler;
|
||||||
clientHandler.AllowAutoRedirect = true;
|
|
||||||
clientHandler.UseProxy = true;
|
clientHandler.UseProxy = true;
|
||||||
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
|
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,16 +23,8 @@ internal sealed partial class ExceptionRecorder
|
|||||||
public void Record(Application app)
|
public void Record(Application app)
|
||||||
{
|
{
|
||||||
app.UnhandledException += OnAppUnhandledException;
|
app.UnhandledException += OnAppUnhandledException;
|
||||||
app.DebugSettings.FailFastOnErrors = false;
|
|
||||||
|
|
||||||
app.DebugSettings.IsBindingTracingEnabled = true;
|
|
||||||
app.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
app.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||||
|
|
||||||
app.DebugSettings.IsXamlResourceReferenceTracingEnabled = true;
|
|
||||||
app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||||
|
|
||||||
app.DebugSettings.LayoutCycleTracingLevel = LayoutCycleTracingLevel.High;
|
|
||||||
app.DebugSettings.LayoutCycleDebugBreakLevel = LayoutCycleDebugBreakLevel.High;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("", "CA2012")]
|
[SuppressMessage("", "CA2012")]
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// 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 System.Numerics;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.ExceptionService;
|
namespace Snap.Hutao.Core.ExceptionService;
|
||||||
|
|
||||||
internal sealed class HutaoException : Exception
|
internal sealed class HutaoException : Exception
|
||||||
@@ -39,10 +37,4 @@ internal sealed class HutaoException : Exception
|
|||||||
string message = $"This instance of '{typeof(TFrom).FullName}' '{name}' doesn't implement '{typeof(TTo).FullName}'";
|
string message = $"This instance of '{typeof(TFrom).FullName}' '{name}' doesn't implement '{typeof(TTo).FullName}'";
|
||||||
throw new HutaoException(HutaoExceptionKind.ServiceTypeCastFailed, message, innerException);
|
throw new HutaoException(HutaoExceptionKind.ServiceTypeCastFailed, message, innerException);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HutaoException GachaStatisticsInvalidItemId(uint id, Exception? innerException = default)
|
|
||||||
{
|
|
||||||
string message = SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(id);
|
|
||||||
throw new HutaoException(HutaoExceptionKind.GachaStatisticsInvalidItemId, message, innerException);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,5 +9,4 @@ internal enum HutaoExceptionKind
|
|||||||
ServiceTypeCastFailed,
|
ServiceTypeCastFailed,
|
||||||
FileSystemCreateFileInsufficientPermissions,
|
FileSystemCreateFileInsufficientPermissions,
|
||||||
PrivateNamedPipeContentHashIncorrect,
|
PrivateNamedPipeContentHashIncorrect,
|
||||||
GachaStatisticsInvalidItemId,
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
using System.Collections.Frozen;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core;
|
namespace Snap.Hutao.Core;
|
||||||
@@ -15,25 +14,25 @@ internal static class TypeNameHelper
|
|||||||
{
|
{
|
||||||
private const char DefaultNestedTypeDelimiter = '+';
|
private const char DefaultNestedTypeDelimiter = '+';
|
||||||
|
|
||||||
private static readonly FrozenDictionary<Type, string> BuiltInTypeNames = FrozenDictionary.ToFrozenDictionary(
|
private static readonly Dictionary<Type, string> BuiltInTypeNames = new()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(typeof(void), "void"),
|
{ typeof(void), "void" },
|
||||||
KeyValuePair.Create(typeof(bool), "bool"),
|
{ typeof(bool), "bool" },
|
||||||
KeyValuePair.Create(typeof(byte), "byte"),
|
{ typeof(byte), "byte" },
|
||||||
KeyValuePair.Create(typeof(char), "char"),
|
{ typeof(char), "char" },
|
||||||
KeyValuePair.Create(typeof(decimal), "decimal"),
|
{ typeof(decimal), "decimal" },
|
||||||
KeyValuePair.Create(typeof(double), "double"),
|
{ typeof(double), "double" },
|
||||||
KeyValuePair.Create(typeof(float), "float"),
|
{ typeof(float), "float" },
|
||||||
KeyValuePair.Create(typeof(int), "int"),
|
{ typeof(int), "int" },
|
||||||
KeyValuePair.Create(typeof(long), "long"),
|
{ typeof(long), "long" },
|
||||||
KeyValuePair.Create(typeof(object), "object"),
|
{ typeof(object), "object" },
|
||||||
KeyValuePair.Create(typeof(sbyte), "sbyte"),
|
{ typeof(sbyte), "sbyte" },
|
||||||
KeyValuePair.Create(typeof(short), "short"),
|
{ typeof(short), "short" },
|
||||||
KeyValuePair.Create(typeof(string), "string"),
|
{ typeof(string), "string" },
|
||||||
KeyValuePair.Create(typeof(uint), "uint"),
|
{ typeof(uint), "uint" },
|
||||||
KeyValuePair.Create(typeof(ulong), "ulong"),
|
{ typeof(ulong), "ulong" },
|
||||||
KeyValuePair.Create(typeof(ushort), "ushort"),
|
{ typeof(ushort), "ushort" },
|
||||||
]);
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取对象类型的显示名称
|
/// 获取对象类型的显示名称
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ namespace Snap.Hutao.Extension;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal static partial class EnumerableExtension
|
internal static partial class EnumerableExtension
|
||||||
{
|
{
|
||||||
public static void Deconstruct<TKey, TElement>(this IGrouping<TKey, TElement> grouping, out TKey key, out IEnumerable<TElement> elements)
|
|
||||||
{
|
|
||||||
key = grouping.Key;
|
|
||||||
elements = grouping;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TElement? ElementAtOrLastOrDefault<TElement>(this IEnumerable<TElement> source, int index)
|
public static TElement? ElementAtOrLastOrDefault<TElement>(this IEnumerable<TElement> source, int index)
|
||||||
{
|
{
|
||||||
return source.ElementAtOrDefault(index) ?? source.LastOrDefault();
|
return source.ElementAtOrDefault(index) ?? source.LastOrDefault();
|
||||||
|
|||||||
@@ -41,30 +41,6 @@
|
|||||||
"Equatable": true,
|
"Equatable": true,
|
||||||
"EqualityOperators": true
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"Name": "FurnitureId",
|
|
||||||
"Documentation": "家具 Id",
|
|
||||||
"Equatable": true,
|
|
||||||
"EqualityOperators": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "FurnitureMakeId",
|
|
||||||
"Documentation": "家具配方 Id",
|
|
||||||
"Equatable": true,
|
|
||||||
"EqualityOperators": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "FurnitureSuiteId",
|
|
||||||
"Documentation": "家具套装 Id",
|
|
||||||
"Equatable": true,
|
|
||||||
"EqualityOperators": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "FurnitureTypeId",
|
|
||||||
"Documentation": "家具分类 Id",
|
|
||||||
"Equatable": true,
|
|
||||||
"EqualityOperators": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"Name": "Level",
|
"Name": "Level",
|
||||||
"Documentation": "等级 1 - 90",
|
"Documentation": "等级 1 - 90",
|
||||||
|
|||||||
@@ -42,14 +42,14 @@ internal sealed partial class GachaItem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿记录分类
|
/// 祈愿记录分类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GachaType GachaType { get; set; }
|
public GachaConfigType GachaType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿记录查询分类
|
/// 祈愿记录查询分类
|
||||||
/// 合并保底的卡池使用此属性
|
/// 合并保底的卡池使用此属性
|
||||||
/// 仅4种(不含400)
|
/// 仅4种(不含400)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GachaType QueryType { get; set; }
|
public GachaConfigType QueryType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品Id
|
/// 物品Id
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal sealed class UIGFItem : GachaLogItem, IMappingFrom<UIGFItem, GachaItem,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("uigf_gacha_type")]
|
[JsonPropertyName("uigf_gacha_type")]
|
||||||
[JsonEnum(JsonSerializeType.NumberString)]
|
[JsonEnum(JsonSerializeType.NumberString)]
|
||||||
public GachaType UIGFGachaType { get; set; } = default!;
|
public GachaConfigType UIGFGachaType { get; set; } = default!;
|
||||||
|
|
||||||
public static UIGFItem From(GachaItem item, INameQuality nameQuality)
|
public static UIGFItem From(GachaItem item, INameQuality nameQuality)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Intrinsic;
|
|
||||||
|
|
||||||
internal enum FurnitureDeploySurfaceType
|
|
||||||
{
|
|
||||||
Ground = 0,
|
|
||||||
Wall = 1,
|
|
||||||
Ceil = 2,
|
|
||||||
StackObjPlane = 3,
|
|
||||||
Door = 4,
|
|
||||||
Chandelier = 5,
|
|
||||||
Floor = 6,
|
|
||||||
WallBody = 7,
|
|
||||||
Carpet = 8,
|
|
||||||
LegoRockery = 9,
|
|
||||||
Stair = 10,
|
|
||||||
NPC = 11,
|
|
||||||
Animal = 12,
|
|
||||||
Apartment = 13,
|
|
||||||
FurnitureSuite = 14,
|
|
||||||
Road = 15,
|
|
||||||
Terrain = 16,
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Intrinsic;
|
|
||||||
|
|
||||||
internal enum FurnitureDeployType
|
|
||||||
{
|
|
||||||
Interior,
|
|
||||||
Exterior,
|
|
||||||
InteriorRoom,
|
|
||||||
InteriorHall,
|
|
||||||
Skybox,
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Intrinsic;
|
|
||||||
|
|
||||||
internal enum GroupRecordType
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Racing,
|
|
||||||
Balloon,
|
|
||||||
Stake,
|
|
||||||
Seek,
|
|
||||||
Explosion,
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Intrinsic;
|
|
||||||
|
|
||||||
internal enum SpecialFurnitureType
|
|
||||||
{
|
|
||||||
NormalFurniture,
|
|
||||||
BlockDependent,
|
|
||||||
FarmField,
|
|
||||||
TeleportPoint,
|
|
||||||
Fishpond,
|
|
||||||
Npc,
|
|
||||||
Apartment,
|
|
||||||
FurnitureSuite,
|
|
||||||
Paimon,
|
|
||||||
Fish,
|
|
||||||
CustomBaseFurniture,
|
|
||||||
CustomNodeFurniture,
|
|
||||||
VirtualFurniture,
|
|
||||||
GroupFurniture,
|
|
||||||
CoopPictureFrame,
|
|
||||||
ChangeBgmFurniture,
|
|
||||||
ServerGadget,
|
|
||||||
Fishtank,
|
|
||||||
}
|
|
||||||
@@ -8,4 +8,15 @@ namespace Snap.Hutao.Model.Metadata.Achievement;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 奖励
|
/// 奖励
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class Reward : IdCount;
|
internal sealed class Reward
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public MaterialId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数量
|
||||||
|
/// </summary>
|
||||||
|
public uint Count { get; set; }
|
||||||
|
}
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Control;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using System.Collections.Frozen;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
|
||||||
|
|
||||||
internal sealed class AssociationTypeIconConverter : ValueConverter<AssociationType, Uri?>
|
|
||||||
{
|
|
||||||
private static readonly FrozenDictionary<string, AssociationType> LocalizedNameToAssociationType = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeMondstadt, AssociationType.ASSOC_TYPE_MONDSTADT),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeLiyue, AssociationType.ASSOC_TYPE_LIYUE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFatui, AssociationType.ASSOC_TYPE_FATUI),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeInazuma, AssociationType.ASSOC_TYPE_INAZUMA),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeRanger, AssociationType.ASSOC_TYPE_RANGER),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSumeru, AssociationType.ASSOC_TYPE_SUMERU),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFontaine, AssociationType.ASSOC_TYPE_FONTAINE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeNatlan, AssociationType.ASSOC_TYPE_NATLAN),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSnezhnaya, AssociationType.ASSOC_TYPE_SNEZHNAYA),
|
|
||||||
]);
|
|
||||||
|
|
||||||
public static Uri? AssociationTypeNameToIconUri(string associationTypeName)
|
|
||||||
{
|
|
||||||
return AssociationTypeToIconUri(LocalizedNameToAssociationType.GetValueOrDefault(associationTypeName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri? AssociationTypeToIconUri(AssociationType type)
|
|
||||||
{
|
|
||||||
string? association = type switch
|
|
||||||
{
|
|
||||||
AssociationType.ASSOC_TYPE_MONDSTADT => "Mengde",
|
|
||||||
AssociationType.ASSOC_TYPE_LIYUE => "Liyue",
|
|
||||||
AssociationType.ASSOC_TYPE_FATUI => default,
|
|
||||||
AssociationType.ASSOC_TYPE_INAZUMA => "Inazuma",
|
|
||||||
AssociationType.ASSOC_TYPE_RANGER => default,
|
|
||||||
AssociationType.ASSOC_TYPE_SUMERU => "Sumeru",
|
|
||||||
AssociationType.ASSOC_TYPE_FONTAINE => "Fontaine",
|
|
||||||
AssociationType.ASSOC_TYPE_NATLAN => default,
|
|
||||||
AssociationType.ASSOC_TYPE_SNEZHNAYA => default,
|
|
||||||
_ => throw Must.NeverHappen(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return association is null
|
|
||||||
? default
|
|
||||||
: Web.HutaoEndpoints.StaticRaw("ChapterIcon", $"UI_ChapterIcon_{association}.png").ToUri();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Uri? Convert(AssociationType from)
|
|
||||||
{
|
|
||||||
return AssociationTypeToIconUri(from);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using System.Collections.Frozen;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
|
||||||
@@ -13,27 +12,27 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class ElementNameIconConverter : ValueConverter<string, Uri>
|
internal sealed class ElementNameIconConverter : ValueConverter<string, Uri>
|
||||||
{
|
{
|
||||||
private static readonly FrozenDictionary<string, string> LocalizedNameToElementIconName = FrozenDictionary.ToFrozenDictionary(
|
private static readonly Dictionary<string, string> LocalizedNameToElementIconName = new()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameElec, "Electric"),
|
[SH.ModelIntrinsicElementNameElec] = "Electric",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameFire, "Fire"),
|
[SH.ModelIntrinsicElementNameFire] = "Fire",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameGrass, "Grass"),
|
[SH.ModelIntrinsicElementNameGrass] = "Grass",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameIce, "Ice"),
|
[SH.ModelIntrinsicElementNameIce] = "Ice",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameRock, "Rock"),
|
[SH.ModelIntrinsicElementNameRock] = "Rock",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWater, "Water"),
|
[SH.ModelIntrinsicElementNameWater] = "Water",
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWind, "Wind"),
|
[SH.ModelIntrinsicElementNameWind] = "Wind",
|
||||||
]);
|
};
|
||||||
|
|
||||||
private static readonly FrozenDictionary<string, ElementType> LocalizedNameToElementType = FrozenDictionary.ToFrozenDictionary(
|
private static readonly Dictionary<string, ElementType> LocalizedNameToElementType = new()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameElec, ElementType.Electric),
|
[SH.ModelIntrinsicElementNameElec] = ElementType.Electric,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameFire, ElementType.Fire),
|
[SH.ModelIntrinsicElementNameFire] = ElementType.Fire,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameGrass, ElementType.Grass),
|
[SH.ModelIntrinsicElementNameGrass] = ElementType.Grass,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameIce, ElementType.Ice),
|
[SH.ModelIntrinsicElementNameIce] = ElementType.Ice,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameRock, ElementType.Rock),
|
[SH.ModelIntrinsicElementNameRock] = ElementType.Rock,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWater, ElementType.Water),
|
[SH.ModelIntrinsicElementNameWater] = ElementType.Water,
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWind, ElementType.Wind),
|
[SH.ModelIntrinsicElementNameWind] = ElementType.Wind,
|
||||||
]);
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将中文元素名称转换为图标链接
|
/// 将中文元素名称转换为图标链接
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.Control.Theme;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using System.Collections.Frozen;
|
using Snap.Hutao.Win32;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||||
@@ -16,39 +15,17 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class QualityColorConverter : ValueConverter<QualityType, Color>
|
internal sealed class QualityColorConverter : ValueConverter<QualityType, Color>
|
||||||
{
|
{
|
||||||
private static readonly FrozenDictionary<string, QualityType> LocalizedNameToQualityType = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityWhite, QualityType.QUALITY_WHITE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityGreen, QualityType.QUALITY_GREEN),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityBlue, QualityType.QUALITY_BLUE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityPurple, QualityType.QUALITY_PURPLE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityOrange, QualityType.QUALITY_ORANGE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityRed, QualityType.QUALITY_ORANGE_SP),
|
|
||||||
]);
|
|
||||||
|
|
||||||
private static readonly FrozenDictionary<QualityType, Color> QualityTypeToColor = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_WHITE, KnownColors.White),
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_GREEN, KnownColors.Green),
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_BLUE, KnownColors.Blue),
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_PURPLE, KnownColors.Purple),
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_ORANGE, KnownColors.Orange),
|
|
||||||
KeyValuePair.Create(QualityType.QUALITY_ORANGE_SP, KnownColors.Orange),
|
|
||||||
]);
|
|
||||||
|
|
||||||
public static Color QualityNameToColor(string qualityName)
|
|
||||||
{
|
|
||||||
return QualityToColor(LocalizedNameToQualityType.GetValueOrDefault(qualityName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color QualityToColor(QualityType quality)
|
|
||||||
{
|
|
||||||
return QualityTypeToColor.GetValueOrDefault(quality, Colors.Transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override Color Convert(QualityType from)
|
public override Color Convert(QualityType from)
|
||||||
{
|
{
|
||||||
return QualityToColor(from);
|
return from switch
|
||||||
|
{
|
||||||
|
QualityType.QUALITY_WHITE => StructMarshal.Color(0xFF72778B),
|
||||||
|
QualityType.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72),
|
||||||
|
QualityType.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB),
|
||||||
|
QualityType.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0),
|
||||||
|
QualityType.QUALITY_ORANGE or QualityType.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932),
|
||||||
|
_ => Colors.Transparent,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using System.Collections.Frozen;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
|
||||||
@@ -13,20 +12,6 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class WeaponTypeIconConverter : ValueConverter<WeaponType, Uri>
|
internal sealed class WeaponTypeIconConverter : ValueConverter<WeaponType, Uri>
|
||||||
{
|
{
|
||||||
private static readonly FrozenDictionary<string, WeaponType> LocalizedNameToWeaponType = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeSwordOneHand, WeaponType.WEAPON_SWORD_ONE_HAND),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeBow, WeaponType.WEAPON_BOW),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypePole, WeaponType.WEAPON_POLE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeClaymore, WeaponType.WEAPON_CLAYMORE),
|
|
||||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeCatalyst, WeaponType.WEAPON_CATALYST),
|
|
||||||
]);
|
|
||||||
|
|
||||||
public static Uri WeaponTypeNameToIconUri(string weaponTypeName)
|
|
||||||
{
|
|
||||||
return WeaponTypeToIconUri(LocalizedNameToWeaponType.GetValueOrDefault(weaponTypeName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将武器类型转换为图标链接
|
/// 将武器类型转换为图标链接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
|
||||||
|
|
||||||
internal sealed class Furniture
|
|
||||||
{
|
|
||||||
public List<FurnitureTypeId> Types { get; set; } = default!;
|
|
||||||
|
|
||||||
public FurnitureDeploySurfaceType SurfaceType { get; set; }
|
|
||||||
|
|
||||||
public bool IsSpecial { get; set; }
|
|
||||||
|
|
||||||
public SpecialFurnitureType SpecialType { get; set; }
|
|
||||||
|
|
||||||
public uint Comfort { get; set; }
|
|
||||||
|
|
||||||
public uint Cost { get; set; }
|
|
||||||
|
|
||||||
public uint DiscountCost { get; set; }
|
|
||||||
|
|
||||||
public bool CanFloat { get; set; }
|
|
||||||
|
|
||||||
public bool IsUnique { get; set; }
|
|
||||||
|
|
||||||
public string? ItemIcon { get; set; }
|
|
||||||
|
|
||||||
public string? EffectIcon { get; set; }
|
|
||||||
|
|
||||||
public QualityType RankLevel { get; set; }
|
|
||||||
|
|
||||||
public List<FurnitureId> GruopUnits { get; set; } = default!;
|
|
||||||
|
|
||||||
public GroupRecordType GroupRecordType { get; set; }
|
|
||||||
|
|
||||||
public List<string> SourceTexts { get; set; } = default!;
|
|
||||||
|
|
||||||
public FurnitureId Id { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; } = default!;
|
|
||||||
|
|
||||||
public string Description { get; set; } = default!;
|
|
||||||
|
|
||||||
public string? Icon { get; set; }
|
|
||||||
|
|
||||||
public uint Rank { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
|
||||||
|
|
||||||
internal sealed class FurnitureMake
|
|
||||||
{
|
|
||||||
public FurnitureMakeId Id { get; set; }
|
|
||||||
|
|
||||||
public FurnitureId ItemId { get; set; }
|
|
||||||
|
|
||||||
public uint Experience { get; set; }
|
|
||||||
|
|
||||||
public List<IdCount> Materials { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
|
||||||
|
|
||||||
internal sealed class FurnitureSuite
|
|
||||||
{
|
|
||||||
public FurnitureSuiteId Id { get; set; }
|
|
||||||
|
|
||||||
public List<FurnitureTypeId> Types { get; set; } = default!;
|
|
||||||
|
|
||||||
public string Name { get; set; } = default!;
|
|
||||||
|
|
||||||
public string Description { get; set; } = default!;
|
|
||||||
|
|
||||||
public string ItemIcon { get; set; } = default!;
|
|
||||||
|
|
||||||
public string? MapIcon { get; set; }
|
|
||||||
|
|
||||||
public List<AvatarId>? FavoriteNpcs { get; set; }
|
|
||||||
|
|
||||||
public List<FurnitureId> Units { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
|
||||||
|
|
||||||
internal sealed class FurnitureType
|
|
||||||
{
|
|
||||||
public FurnitureTypeId Id { get; set; }
|
|
||||||
|
|
||||||
public uint Category { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; } = default!;
|
|
||||||
|
|
||||||
public string Name2 { get; set; } = default!;
|
|
||||||
|
|
||||||
public string TabIcon { get; set; } = default!;
|
|
||||||
|
|
||||||
public FurnitureDeployType SceneType { get; set; }
|
|
||||||
|
|
||||||
public bool BagPageOnly { get; set; }
|
|
||||||
|
|
||||||
public bool IsShowInBag { get; set; }
|
|
||||||
|
|
||||||
public uint Sort { get; set; }
|
|
||||||
}
|
|
||||||
@@ -49,7 +49,7 @@ internal sealed class GachaEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卡池类型
|
/// 卡池类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GachaType Type { get; set; }
|
public GachaConfigType Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 五星列表
|
/// 五星列表
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata;
|
|
||||||
|
|
||||||
internal class IdCount
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Id
|
|
||||||
/// </summary>
|
|
||||||
public MaterialId Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数量
|
|
||||||
/// </summary>
|
|
||||||
public uint Count { get; set; }
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"Snap.Hutao": {
|
"Snap.Hutao": {
|
||||||
"commandName": "MsixPackage",
|
"commandName": "MsixPackage",
|
||||||
"nativeDebugging": true,
|
"nativeDebugging": false,
|
||||||
"doNotLaunchApp": false,
|
"doNotLaunchApp": false,
|
||||||
"allowLocalNetworkLoopbackProperty": true
|
"allowLocalNetworkLoopbackProperty": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -860,9 +860,6 @@
|
|||||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||||
<value>角色活动</value>
|
<value>角色活动</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
|
||||||
<value>集录祈愿</value>
|
|
||||||
</data>
|
|
||||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||||
<value>奔行世间</value>
|
<value>奔行世间</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2636,12 +2633,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>Webview2 运行时</value>
|
<value>Webview2 运行时</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
|
||||||
<value>下半</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
|
||||||
<value>上半</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||||
<value>搭配圣遗物</value>
|
<value>搭配圣遗物</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2904,7 +2895,7 @@
|
|||||||
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
@@ -3056,9 +3047,6 @@
|
|||||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||||
<value>角色活动祈愿-2</value>
|
<value>角色活动祈愿-2</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
|
||||||
<value>集录祈愿</value>
|
|
||||||
</data>
|
|
||||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||||
<value>新手祈愿</value>
|
<value>新手祈愿</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.5 KiB |
@@ -85,13 +85,8 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
|||||||
{
|
{
|
||||||
foreach (ref readonly Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
foreach (ref readonly Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
||||||
{
|
{
|
||||||
item.Subtitle = new StringBuilder(item.Subtitle)
|
item.Subtitle = new StringBuilder(item.Subtitle).Replace("\r<br>", string.Empty).ToString();
|
||||||
.Replace("\r<br>", string.Empty)
|
item.Content = AnnouncementRegex.XmlTimeTagRegex().Replace(item.Content, x => x.Groups[1].Value);
|
||||||
.Replace("<br />", string.Empty)
|
|
||||||
.ToString();
|
|
||||||
item.Content = AnnouncementRegex
|
|
||||||
.XmlTimeTagRegex()
|
|
||||||
.Replace(item.Content, x => x.Groups[1].Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
|||||||
|
|
||||||
private HashSet<string> currentBackgroundPathSet;
|
private HashSet<string> currentBackgroundPathSet;
|
||||||
|
|
||||||
public async ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous)
|
public async ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous)
|
||||||
{
|
{
|
||||||
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync().ConfigureAwait(false);
|
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (backgroundSet.Count <= 0)
|
if (backgroundSet.Count <= 0)
|
||||||
{
|
{
|
||||||
return new(true, default!);
|
return new(false, default!);
|
||||||
}
|
}
|
||||||
|
|
||||||
string path = System.Random.Shared.GetItems([..backgroundSet], 1)[0];
|
string path = System.Random.Shared.GetItems([..backgroundSet], 1)[0];
|
||||||
@@ -109,9 +109,6 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
|||||||
case BackgroundImageType.HutaoOfficialLauncher:
|
case BackgroundImageType.HutaoOfficialLauncher:
|
||||||
await SetCurrentBackgroundPathSetAsync(client => client.GetLauncherWallpaperAsync()).ConfigureAwait(false);
|
await SetCurrentBackgroundPathSetAsync(client => client.GetLauncherWallpaperAsync()).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
currentBackgroundPathSet = [];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentBackgroundPathSet ??= [];
|
currentBackgroundPathSet ??= [];
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.BackgroundImage;
|
|||||||
|
|
||||||
internal interface IBackgroundImageService
|
internal interface IBackgroundImageService
|
||||||
{
|
{
|
||||||
ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous);
|
ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous);
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
||||||
|
|
||||||
List<InventoryItemView> results = [];
|
List<InventoryItemView> results = [];
|
||||||
foreach (Material meta in context.EnumerateInventoryMaterial())
|
foreach (Material meta in context.EnumerateInventroyMaterial())
|
||||||
{
|
{
|
||||||
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
||||||
results.Add(new(entity, meta, saveCommand));
|
results.Add(new(entity, meta, saveCommand));
|
||||||
|
|||||||
@@ -41,33 +41,39 @@ internal sealed partial class DiscordService : IDiscordService, IDisposable
|
|||||||
|
|
||||||
private bool IsSupported()
|
private bool IsSupported()
|
||||||
{
|
{
|
||||||
// Actually requires a discord client to be running on Windows platform.
|
try
|
||||||
// If not, discord core creation code will throw.
|
|
||||||
Process[] discordProcesses = Process.GetProcessesByName("Discord");
|
|
||||||
|
|
||||||
if (discordProcesses.Length <= 0)
|
|
||||||
{
|
{
|
||||||
return false;
|
// Actually requires a discord client to be running on Windows platform.
|
||||||
}
|
// If not, discord core creation code will throw.
|
||||||
|
Process[] discordProcesses = Process.GetProcessesByName("Discord");
|
||||||
|
|
||||||
foreach (Process process in discordProcesses)
|
if (discordProcesses.Length <= 0)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
_ = process.Handle;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
if (!isInitialized)
|
|
||||||
{
|
|
||||||
isInitialized = true;
|
|
||||||
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
foreach (Process process in discordProcesses)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = process.Handle;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (!isInitialized)
|
||||||
|
{
|
||||||
|
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isInitialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
using System.Collections.Frozen;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 祈愿配置类型比较器
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class GachaConfigTypeComparer : IComparer<GachaConfigType>
|
||||||
|
{
|
||||||
|
private static readonly Lazy<GachaConfigTypeComparer> LazyShared = new(() => new());
|
||||||
|
private static readonly FrozenDictionary<GachaConfigType, int> OrderMap = new Dictionary<GachaConfigType, int>()
|
||||||
|
{
|
||||||
|
[GachaConfigType.AvatarEventWish] = 0,
|
||||||
|
[GachaConfigType.AvatarEventWish2] = 1,
|
||||||
|
[GachaConfigType.WeaponEventWish] = 2,
|
||||||
|
[GachaConfigType.StandardWish] = 3,
|
||||||
|
[GachaConfigType.NoviceWish] = 4,
|
||||||
|
}.ToFrozenDictionary();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 共享的比较器
|
||||||
|
/// </summary>
|
||||||
|
public static GachaConfigTypeComparer Shared { get => LazyShared.Value; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Compare(GachaConfigType x, GachaConfigType y)
|
||||||
|
{
|
||||||
|
return OrderOf(x) - OrderOf(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int OrderOf(GachaConfigType type)
|
||||||
|
{
|
||||||
|
return OrderMap.GetValueOrDefault(type, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
@@ -26,7 +25,7 @@ internal static class GachaStatisticsExtension
|
|||||||
bool isPreviousUp = true;
|
bool isPreviousUp = true;
|
||||||
|
|
||||||
// mark the IsGuarantee
|
// mark the IsGuarantee
|
||||||
foreach (ref readonly SummaryItem item in CollectionsMarshal.AsSpan(summaryItems))
|
foreach (SummaryItem item in summaryItems)
|
||||||
{
|
{
|
||||||
if (item.IsUp && (!isPreviousUp))
|
if (item.IsUp && (!isPreviousUp))
|
||||||
{
|
{
|
||||||
@@ -63,4 +62,4 @@ internal static class GachaStatisticsExtension
|
|||||||
ReadOnlySpan<byte> codes = MD5.HashData(Encoding.UTF8.GetBytes(name));
|
ReadOnlySpan<byte> codes = MD5.HashData(Encoding.UTF8.GetBytes(name));
|
||||||
return Color.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average());
|
return Color.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Snap.Hutao.Model.Metadata;
|
|||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
@@ -32,8 +31,9 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
|
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventListAsync().ConfigureAwait(false);
|
||||||
|
List<HistoryWishBuilder> historyWishBuilders = gachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
||||||
|
|
||||||
List<HistoryWishBuilder> historyWishBuilders = context.GachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
|
||||||
return CreateCore(taskContext, homaGachaLogClient, items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
return CreateCore(taskContext, homaGachaLogClient, items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +54,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
TypedWishSummaryBuilderContext weaponContext = TypedWishSummaryBuilderContext.WeaponEventWish(taskContext, gachaLogClient);
|
TypedWishSummaryBuilderContext weaponContext = TypedWishSummaryBuilderContext.WeaponEventWish(taskContext, gachaLogClient);
|
||||||
TypedWishSummaryBuilder weaponWishBuilder = new(weaponContext);
|
TypedWishSummaryBuilder weaponWishBuilder = new(weaponContext);
|
||||||
|
|
||||||
TypedWishSummaryBuilderContext chronicledContext = TypedWishSummaryBuilderContext.ChronicledWish(taskContext, gachaLogClient);
|
|
||||||
TypedWishSummaryBuilder chronicledWishBuilder = new(chronicledContext);
|
|
||||||
|
|
||||||
Dictionary<Avatar, int> orangeAvatarCounter = [];
|
Dictionary<Avatar, int> orangeAvatarCounter = [];
|
||||||
Dictionary<Avatar, int> purpleAvatarCounter = [];
|
Dictionary<Avatar, int> purpleAvatarCounter = [];
|
||||||
Dictionary<Weapon, int> orangeWeaponCounter = [];
|
Dictionary<Weapon, int> orangeWeaponCounter = [];
|
||||||
@@ -64,25 +61,24 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
Dictionary<Weapon, int> blueWeaponCounter = [];
|
Dictionary<Weapon, int> blueWeaponCounter = [];
|
||||||
|
|
||||||
// Pre group builders
|
// Pre group builders
|
||||||
Dictionary<GachaType, List<HistoryWishBuilder>> historyWishBuilderMap = historyWishBuilders
|
Dictionary<GachaConfigType, List<HistoryWishBuilder>> historyWishBuilderMap = historyWishBuilders
|
||||||
.GroupBy(b => b.ConfigType)
|
.GroupBy(b => b.ConfigType)
|
||||||
.ToDictionary(g => g.Key, g => g.ToList().SortBy(b => b.From));
|
.ToDictionary(g => g.Key, g => g.ToList().SortBy(b => b.From));
|
||||||
|
|
||||||
// Items are ordered by precise time, first is oldest
|
// Items are ordered by precise time, first is oldest
|
||||||
// 'ref' is not allowed here because we have lambda below
|
// 'ref' is not allowed here because we have lambda below
|
||||||
foreach (ref readonly Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
|
foreach (Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||||
{
|
{
|
||||||
// Find target history wish to operate. // banner.From <= item.Time <= banner.To
|
// Find target history wish to operate. // w.From <= item.Time <= w.To
|
||||||
Model.Entity.GachaItem pinned = item;
|
HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaConfigType.StandardWish or GachaConfigType.NoviceWish)
|
||||||
HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaType.Standard or GachaType.NewBie)
|
? historyWishBuilderMap[item.GachaType].BinarySearch(w => item.Time < w.From ? -1 : item.Time > w.To ? 1 : 0)
|
||||||
? historyWishBuilderMap[item.GachaType].BinarySearch(banner => pinned.Time < banner.From ? -1 : pinned.Time > banner.To ? 1 : 0)
|
|
||||||
: default;
|
: default;
|
||||||
|
|
||||||
switch (item.ItemId.StringLength())
|
switch (item.ItemId.StringLength())
|
||||||
{
|
{
|
||||||
case 8U:
|
case 8U:
|
||||||
{
|
{
|
||||||
Avatar avatar = context.GetAvatar(item.ItemId);
|
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
||||||
|
|
||||||
bool isUp = false;
|
bool isUp = false;
|
||||||
switch (avatar.Quality)
|
switch (avatar.Quality)
|
||||||
@@ -102,7 +98,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
standardWishBuilder.Track(item, avatar, isUp);
|
standardWishBuilder.Track(item, avatar, isUp);
|
||||||
avatarWishBuilder.Track(item, avatar, isUp);
|
avatarWishBuilder.Track(item, avatar, isUp);
|
||||||
weaponWishBuilder.Track(item, avatar, isUp);
|
weaponWishBuilder.Track(item, avatar, isUp);
|
||||||
chronicledWishBuilder.Track(item, avatar, isUp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,18 +127,17 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
standardWishBuilder.Track(item, weapon, isUp);
|
standardWishBuilder.Track(item, weapon, isUp);
|
||||||
avatarWishBuilder.Track(item, weapon, isUp);
|
avatarWishBuilder.Track(item, weapon, isUp);
|
||||||
weaponWishBuilder.Track(item, weapon, isUp);
|
weaponWishBuilder.Track(item, weapon, isUp);
|
||||||
chronicledWishBuilder.Track(item, weapon, isUp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// ItemId string length not correct.
|
// ItemId string length not correct.
|
||||||
HutaoException.GachaStatisticsInvalidItemId(item.ItemId);
|
ThrowHelper.UserdataCorrupted(SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(item.ItemId), default!);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncBarrier barrier = new(4);
|
AsyncBarrier barrier = new(3);
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -151,7 +145,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
HistoryWishes = historyWishBuilders
|
HistoryWishes = historyWishBuilders
|
||||||
.Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty))
|
.Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty))
|
||||||
.OrderByDescending(builder => builder.From)
|
.OrderByDescending(builder => builder.From)
|
||||||
.ThenBy(builder => builder.ConfigType, GachaTypeComparer.Shared)
|
.ThenBy(builder => builder.ConfigType, GachaConfigTypeComparer.Shared)
|
||||||
.Select(builder => builder.ToHistoryWish())
|
.Select(builder => builder.ToHistoryWish())
|
||||||
.ToList(),
|
.ToList(),
|
||||||
|
|
||||||
@@ -168,7 +162,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
StandardWish = standardWishBuilder.ToTypedWishSummary(barrier),
|
StandardWish = standardWishBuilder.ToTypedWishSummary(barrier),
|
||||||
AvatarWish = avatarWishBuilder.ToTypedWishSummary(barrier),
|
AvatarWish = avatarWishBuilder.ToTypedWishSummary(barrier),
|
||||||
WeaponWish = weaponWishBuilder.ToTypedWishSummary(barrier),
|
WeaponWish = weaponWishBuilder.ToTypedWishSummary(barrier),
|
||||||
ChronicledWish = chronicledWishBuilder.ToTypedWishSummary(barrier),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,29 +62,22 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF
|
|||||||
int weaponPurpleTracker = 0;
|
int weaponPurpleTracker = 0;
|
||||||
TypedWishSummarySlim weaponWish = new(SH.ServiceGachaLogFactoryWeaponWishName, 80, 10);
|
TypedWishSummarySlim weaponWish = new(SH.ServiceGachaLogFactoryWeaponWishName, 80, 10);
|
||||||
|
|
||||||
int chronicledOrangeTracker = 0;
|
|
||||||
int chronicledPurpleTracker = 0;
|
|
||||||
TypedWishSummarySlim chronicledWish = new(SH.ServiceGachaLogFactoryChronicledWishName, 90, 10);
|
|
||||||
|
|
||||||
// O(n) operation
|
// O(n) operation
|
||||||
foreach (ref readonly GachaItem item in CollectionsMarshal.AsSpan(items))
|
foreach (ref readonly GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||||
{
|
{
|
||||||
INameQuality nameQuality = context.GetNameQualityByItemId(item.ItemId);
|
INameQuality nameQuality = context.GetNameQualityByItemId(item.ItemId);
|
||||||
switch (item.QueryType)
|
switch (item.QueryType)
|
||||||
{
|
{
|
||||||
case GachaType.Standard:
|
case GachaConfigType.StandardWish:
|
||||||
Track(nameQuality, ref standardOrangeTracker, ref standardPurpleTracker);
|
Track(nameQuality, ref standardOrangeTracker, ref standardPurpleTracker);
|
||||||
break;
|
break;
|
||||||
case GachaType.ActivityAvatar:
|
case GachaConfigType.AvatarEventWish:
|
||||||
case GachaType.SpecialActivityAvatar:
|
case GachaConfigType.AvatarEventWish2:
|
||||||
Track(nameQuality, ref avatarOrangeTracker, ref avatarPurpleTracker);
|
Track(nameQuality, ref avatarOrangeTracker, ref avatarPurpleTracker);
|
||||||
break;
|
break;
|
||||||
case GachaType.ActivityWeapon:
|
case GachaConfigType.WeaponEventWish:
|
||||||
Track(nameQuality, ref weaponOrangeTracker, ref weaponPurpleTracker);
|
Track(nameQuality, ref weaponOrangeTracker, ref weaponPurpleTracker);
|
||||||
break;
|
break;
|
||||||
case GachaType.ActivityCity:
|
|
||||||
Track(nameQuality, ref chronicledOrangeTracker, ref chronicledPurpleTracker);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -92,16 +85,11 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF
|
|||||||
|
|
||||||
standardWish.LastOrangePull = standardOrangeTracker;
|
standardWish.LastOrangePull = standardOrangeTracker;
|
||||||
standardWish.LastPurplePull = standardPurpleTracker;
|
standardWish.LastPurplePull = standardPurpleTracker;
|
||||||
|
|
||||||
avatarWish.LastOrangePull = avatarOrangeTracker;
|
avatarWish.LastOrangePull = avatarOrangeTracker;
|
||||||
avatarWish.LastPurplePull = avatarPurpleTracker;
|
avatarWish.LastPurplePull = avatarPurpleTracker;
|
||||||
|
|
||||||
weaponWish.LastOrangePull = weaponOrangeTracker;
|
weaponWish.LastOrangePull = weaponOrangeTracker;
|
||||||
weaponWish.LastPurplePull = weaponPurpleTracker;
|
weaponWish.LastPurplePull = weaponPurpleTracker;
|
||||||
|
|
||||||
chronicledWish.LastOrangePull = chronicledOrangeTracker;
|
|
||||||
chronicledWish.LastPurplePull = chronicledPurpleTracker;
|
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Uid = uid,
|
Uid = uid,
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
|
||||||
using System.Collections.Frozen;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 祈愿配置类型比较器
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class GachaTypeComparer : IComparer<GachaType>
|
|
||||||
{
|
|
||||||
private static readonly Lazy<GachaTypeComparer> LazyShared = new(() => new());
|
|
||||||
private static readonly FrozenDictionary<GachaType, int> OrderMap = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
KeyValuePair.Create(GachaType.ActivityAvatar, 0),
|
|
||||||
KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1),
|
|
||||||
KeyValuePair.Create(GachaType.ActivityWeapon, 2),
|
|
||||||
KeyValuePair.Create(GachaType.Standard, 3),
|
|
||||||
KeyValuePair.Create(GachaType.NewBie, 4),
|
|
||||||
KeyValuePair.Create(GachaType.ActivityCity, 5),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 共享的比较器
|
|
||||||
/// </summary>
|
|
||||||
public static GachaTypeComparer Shared { get => LazyShared.Value; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Compare(GachaType x, GachaType y)
|
|
||||||
{
|
|
||||||
return OrderOf(x) - OrderOf(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static int OrderOf(GachaType type)
|
|
||||||
{
|
|
||||||
return OrderMap.GetValueOrDefault(type, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,7 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gachaEvent">卡池配置</param>
|
/// <param name="gachaEvent">卡池配置</param>
|
||||||
/// <param name="context">祈愿记录上下文</param>
|
/// <param name="context">祈愿记录上下文</param>
|
||||||
|
[SuppressMessage("", "SH002")]
|
||||||
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context)
|
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context)
|
||||||
{
|
{
|
||||||
this.gachaEvent = gachaEvent;
|
this.gachaEvent = gachaEvent;
|
||||||
@@ -36,27 +37,21 @@ internal sealed class HistoryWishBuilder
|
|||||||
|
|
||||||
switch (ConfigType)
|
switch (ConfigType)
|
||||||
{
|
{
|
||||||
case GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar:
|
case GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2:
|
||||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||||
break;
|
break;
|
||||||
case GachaType.ActivityWeapon:
|
case GachaConfigType.WeaponEventWish:
|
||||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||||
break;
|
break;
|
||||||
case GachaType.ActivityCity:
|
|
||||||
|
|
||||||
// Avatars are less than weapons, so we try to get the value from avatar map first
|
|
||||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => (IStatisticsItemSource?)context.IdAvatarMap.GetValueOrDefault(id) ?? context.IdWeaponMap[id]).ToDictionary(c => c, c => 0);
|
|
||||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => (IStatisticsItemSource?)context.IdAvatarMap.GetValueOrDefault(id) ?? context.IdWeaponMap[id]).ToDictionary(c => c, c => 0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿配置类型
|
/// 祈愿配置类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GachaType ConfigType { get; }
|
public GachaConfigType ConfigType { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="GachaEvent.From"/>
|
/// <inheritdoc cref="GachaEvent.From"/>
|
||||||
public DateTimeOffset From { get => gachaEvent.From; }
|
public DateTimeOffset From { get => gachaEvent.From; }
|
||||||
@@ -111,13 +106,13 @@ internal sealed class HistoryWishBuilder
|
|||||||
{
|
{
|
||||||
HistoryWish historyWish = new()
|
HistoryWish historyWish = new()
|
||||||
{
|
{
|
||||||
// Base
|
// base
|
||||||
Name = gachaEvent.Name,
|
Name = gachaEvent.Name,
|
||||||
From = gachaEvent.From,
|
From = gachaEvent.From,
|
||||||
To = gachaEvent.To,
|
To = gachaEvent.To,
|
||||||
TotalCount = totalCountTracker,
|
TotalCount = totalCountTracker,
|
||||||
|
|
||||||
// Fill
|
// fill
|
||||||
Version = gachaEvent.Version,
|
Version = gachaEvent.Version,
|
||||||
BannerImage = gachaEvent.Banner,
|
BannerImage = gachaEvent.Banner,
|
||||||
OrangeUpList = orangeUpCounter.ToStatisticsList(),
|
OrangeUpList = orangeUpCounter.ToStatisticsList(),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Snap.Hutao.Core.ExceptionService;
|
|||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
@@ -19,20 +18,18 @@ internal sealed class HutaoStatisticsFactory
|
|||||||
private readonly GachaEvent avatarEvent;
|
private readonly GachaEvent avatarEvent;
|
||||||
private readonly GachaEvent avatarEvent2;
|
private readonly GachaEvent avatarEvent2;
|
||||||
private readonly GachaEvent weaponEvent;
|
private readonly GachaEvent weaponEvent;
|
||||||
private readonly GachaEvent chronicledEvent;
|
|
||||||
|
|
||||||
public HutaoStatisticsFactory(in HutaoStatisticsFactoryMetadataContext context)
|
public HutaoStatisticsFactory(in HutaoStatisticsFactoryMetadataContext context)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
// when in new verion
|
// TODO: when in new verion
|
||||||
// due to lack of newer metadata
|
// due to lack of newer metadata
|
||||||
// this can crash
|
// this can crash
|
||||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||||
avatarEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityAvatar);
|
avatarEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.AvatarEventWish);
|
||||||
avatarEvent2 = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.SpecialActivityAvatar);
|
avatarEvent2 = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.AvatarEventWish2);
|
||||||
weaponEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityWeapon);
|
weaponEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.WeaponEventWish);
|
||||||
chronicledEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityCity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HutaoStatistics Create(GachaEventStatistics raw)
|
public HutaoStatistics Create(GachaEventStatistics raw)
|
||||||
@@ -41,8 +38,7 @@ internal sealed class HutaoStatisticsFactory
|
|||||||
{
|
{
|
||||||
AvatarEvent = CreateWishSummary(avatarEvent, raw.AvatarEvent),
|
AvatarEvent = CreateWishSummary(avatarEvent, raw.AvatarEvent),
|
||||||
AvatarEvent2 = CreateWishSummary(avatarEvent2, raw.AvatarEvent2),
|
AvatarEvent2 = CreateWishSummary(avatarEvent2, raw.AvatarEvent2),
|
||||||
WeaponEvent = CreateWishSummary(weaponEvent, raw.WeaponEvent),
|
WeaponWish = CreateWishSummary(weaponEvent, raw.WeaponEvent),
|
||||||
Chronicled = CreateWishSummary(chronicledEvent, raw.Chronicled),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +53,12 @@ internal sealed class HutaoStatisticsFactory
|
|||||||
{
|
{
|
||||||
IStatisticsItemSource source = item.Item.StringLength() switch
|
IStatisticsItemSource source = item.Item.StringLength() switch
|
||||||
{
|
{
|
||||||
8U => context.GetAvatar(item.Item),
|
8U => context.IdAvatarMap[item.Item],
|
||||||
5U => context.GetWeapon(item.Item),
|
5U => context.IdWeaponMap[item.Item],
|
||||||
_ => throw HutaoException.GachaStatisticsInvalidItemId(item.Item),
|
_ => throw ThrowHelper.UserdataCorrupted(SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(item.Item), default!),
|
||||||
};
|
};
|
||||||
StatisticsItem statisticsItem = source.ToStatisticsItem(unchecked((int)item.Count));
|
StatisticsItem statisticsItem = source.ToStatisticsItem(unchecked((int)item.Count));
|
||||||
|
|
||||||
// Put UP items to a separate list
|
|
||||||
if (gachaEvent.UpOrangeList.Contains(item.Item) || gachaEvent.UpPurpleList.Contains(item.Item))
|
if (gachaEvent.UpOrangeList.Contains(item.Item) || gachaEvent.UpPurpleList.Contains(item.Item))
|
||||||
{
|
{
|
||||||
upItems.Add(statisticsItem);
|
upItems.Add(statisticsItem);
|
||||||
|
|||||||
@@ -5,18 +5,19 @@ using Snap.Hutao.Model.Metadata;
|
|||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
|
|
||||||
internal sealed class HutaoStatisticsFactoryMetadataContext : IMetadataContext,
|
internal readonly struct HutaoStatisticsFactoryMetadataContext
|
||||||
IMetadataDictionaryIdAvatarSource,
|
|
||||||
IMetadataDictionaryIdWeaponSource,
|
|
||||||
IMetadataListGachaEventSource
|
|
||||||
{
|
{
|
||||||
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
public readonly Dictionary<AvatarId, Avatar> IdAvatarMap;
|
||||||
|
public readonly Dictionary<WeaponId, Weapon> IdWeaponMap;
|
||||||
|
public readonly List<GachaEvent> GachaEvents;
|
||||||
|
|
||||||
public Dictionary<WeaponId, Weapon> IdWeaponMap { get; set; } = default!;
|
public HutaoStatisticsFactoryMetadataContext(Dictionary<AvatarId, Avatar> idAvatarMap, Dictionary<WeaponId, Weapon> idWeaponMap, List<GachaEvent> gachaEvents)
|
||||||
|
{
|
||||||
public List<GachaEvent> GachaEvents { get; set; } = default!;
|
IdAvatarMap = idAvatarMap;
|
||||||
|
IdWeaponMap = idWeaponMap;
|
||||||
|
GachaEvents = gachaEvents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,21 @@ namespace Snap.Hutao.Service.GachaLog.Factory;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class TypedWishSummaryBuilder
|
internal sealed class TypedWishSummaryBuilder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 常驻祈愿
|
||||||
|
/// </summary>
|
||||||
|
public static readonly Func<GachaConfigType, bool> IsStandardWish = type => type is GachaConfigType.StandardWish;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色活动
|
||||||
|
/// </summary>
|
||||||
|
public static readonly Func<GachaConfigType, bool> IsAvatarEventWish = type => type is GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器活动
|
||||||
|
/// </summary>
|
||||||
|
public static readonly Func<GachaConfigType, bool> IsWeaponEventWish = type => type is GachaConfigType.WeaponEventWish;
|
||||||
|
|
||||||
private readonly TypedWishSummaryBuilderContext context;
|
private readonly TypedWishSummaryBuilderContext context;
|
||||||
|
|
||||||
private readonly List<int> averageOrangePullTracker = [];
|
private readonly List<int> averageOrangePullTracker = [];
|
||||||
@@ -47,54 +62,52 @@ internal sealed class TypedWishSummaryBuilder
|
|||||||
/// <param name="isUp">是否为Up物品</param>
|
/// <param name="isUp">是否为Up物品</param>
|
||||||
public void Track(GachaItem item, ISummaryItemSource source, bool isUp)
|
public void Track(GachaItem item, ISummaryItemSource source, bool isUp)
|
||||||
{
|
{
|
||||||
if (!context.TypeEvaluator(item.GachaType))
|
if (context.TypeEvaluator(item.GachaType))
|
||||||
{
|
{
|
||||||
return;
|
++lastOrangePullTracker;
|
||||||
}
|
++lastPurplePullTracker;
|
||||||
|
++lastUpOrangePullTracker;
|
||||||
|
|
||||||
++lastOrangePullTracker;
|
// track total pulls
|
||||||
++lastPurplePullTracker;
|
++totalCountTracker;
|
||||||
++lastUpOrangePullTracker;
|
TrackFromToTime(item.Time);
|
||||||
|
|
||||||
// track total pulls
|
switch (source.Quality)
|
||||||
++totalCountTracker;
|
{
|
||||||
TrackFromToTime(item.Time);
|
case QualityType.QUALITY_ORANGE:
|
||||||
|
|
||||||
switch (source.Quality)
|
|
||||||
{
|
|
||||||
case QualityType.QUALITY_ORANGE:
|
|
||||||
{
|
|
||||||
TrackMinMaxOrangePull(lastOrangePullTracker);
|
|
||||||
averageOrangePullTracker.Add(lastOrangePullTracker);
|
|
||||||
|
|
||||||
if (isUp)
|
|
||||||
{
|
{
|
||||||
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
TrackMinMaxOrangePull(lastOrangePullTracker);
|
||||||
lastUpOrangePullTracker = 0;
|
averageOrangePullTracker.Add(lastOrangePullTracker);
|
||||||
|
|
||||||
|
if (isUp)
|
||||||
|
{
|
||||||
|
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
||||||
|
lastUpOrangePullTracker = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
||||||
|
|
||||||
|
lastOrangePullTracker = 0;
|
||||||
|
++totalOrangePullTracker;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
case QualityType.QUALITY_PURPLE:
|
||||||
|
{
|
||||||
|
lastPurplePullTracker = 0;
|
||||||
|
++totalPurplePullTracker;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
lastOrangePullTracker = 0;
|
case QualityType.QUALITY_BLUE:
|
||||||
++totalOrangePullTracker;
|
{
|
||||||
|
++totalBluePullTracker;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case QualityType.QUALITY_PURPLE:
|
|
||||||
{
|
|
||||||
lastPurplePullTracker = 0;
|
|
||||||
++totalPurplePullTracker;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QualityType.QUALITY_BLUE:
|
|
||||||
{
|
|
||||||
++totalBluePullTracker;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,12 @@ internal readonly struct TypedWishSummaryBuilderContext
|
|||||||
public readonly string Name;
|
public readonly string Name;
|
||||||
public readonly int GuaranteeOrangeThreshold;
|
public readonly int GuaranteeOrangeThreshold;
|
||||||
public readonly int GuaranteePurpleThreshold;
|
public readonly int GuaranteePurpleThreshold;
|
||||||
public readonly Func<GachaType, bool> TypeEvaluator;
|
public readonly Func<GachaConfigType, bool> TypeEvaluator;
|
||||||
public readonly GachaDistributionType DistributionType;
|
public readonly GachaDistributionType DistributionType;
|
||||||
|
|
||||||
private static readonly Func<GachaType, bool> IsStandardWish = type => type is GachaType.Standard;
|
private static readonly Func<GachaConfigType, bool> IsStandardWish = type => type is GachaConfigType.StandardWish;
|
||||||
private static readonly Func<GachaType, bool> IsAvatarEventWish = type => type is GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar;
|
private static readonly Func<GachaConfigType, bool> IsAvatarEventWish = type => type is GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2;
|
||||||
private static readonly Func<GachaType, bool> IsWeaponEventWish = type => type is GachaType.ActivityWeapon;
|
private static readonly Func<GachaConfigType, bool> IsWeaponEventWish = type => type is GachaConfigType.WeaponEventWish;
|
||||||
private static readonly Func<GachaType, bool> IsChronicledWish = type => type is GachaType.ActivityCity;
|
|
||||||
|
|
||||||
public TypedWishSummaryBuilderContext(
|
public TypedWishSummaryBuilderContext(
|
||||||
ITaskContext taskContext,
|
ITaskContext taskContext,
|
||||||
@@ -28,7 +27,7 @@ internal readonly struct TypedWishSummaryBuilderContext
|
|||||||
string name,
|
string name,
|
||||||
int guaranteeOrangeThreshold,
|
int guaranteeOrangeThreshold,
|
||||||
int guaranteePurpleThreshold,
|
int guaranteePurpleThreshold,
|
||||||
Func<GachaType, bool> typeEvaluator,
|
Func<GachaConfigType, bool> typeEvaluator,
|
||||||
GachaDistributionType distributionType)
|
GachaDistributionType distributionType)
|
||||||
{
|
{
|
||||||
TaskContext = taskContext;
|
TaskContext = taskContext;
|
||||||
@@ -55,11 +54,6 @@ internal readonly struct TypedWishSummaryBuilderContext
|
|||||||
return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryWeaponWishName, 80, 10, IsWeaponEventWish, GachaDistributionType.WeaponEvent);
|
return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryWeaponWishName, 80, 10, IsWeaponEventWish, GachaDistributionType.WeaponEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypedWishSummaryBuilderContext ChronicledWish(ITaskContext taskContext, HomaGachaLogClient gachaLogClient)
|
|
||||||
{
|
|
||||||
return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryChronicledWishName, 90, 10, IsChronicledWish, GachaDistributionType.Chronicled);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask<HutaoResponse<GachaDistribution>> GetGachaDistributionAsync()
|
public ValueTask<HutaoResponse<GachaDistribution>> GetGachaDistributionAsync()
|
||||||
{
|
{
|
||||||
return GachaLogClient.GetGachaDistributionAsync(DistributionType);
|
return GachaLogClient.GetGachaDistributionAsync(DistributionType);
|
||||||
|
|||||||
@@ -15,14 +15,12 @@ internal static class GachaArchiveOperation
|
|||||||
{
|
{
|
||||||
archive = archives.SingleOrDefault(a => a.Uid == uid);
|
archive = archives.SingleOrDefault(a => a.Uid == uid);
|
||||||
|
|
||||||
if (archive is not null)
|
if (archive is null)
|
||||||
{
|
{
|
||||||
return;
|
GachaArchive created = GachaArchive.From(uid);
|
||||||
|
gachaLogDbService.AddGachaArchive(created);
|
||||||
|
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
||||||
|
archive = created;
|
||||||
}
|
}
|
||||||
|
|
||||||
GachaArchive created = GachaArchive.From(uid);
|
|
||||||
gachaLogDbService.AddGachaArchive(created);
|
|
||||||
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
|
||||||
archive = created;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 祈愿物品保存上下文
|
||||||
|
/// </summary>
|
||||||
|
internal readonly struct GachaItemSaveContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 待添加物品
|
||||||
|
/// </summary>
|
||||||
|
public readonly List<GachaItem> ItemsToAdd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否懒惰
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsLazy;
|
||||||
|
|
||||||
|
public readonly GachaConfigType QueryType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结尾 Id
|
||||||
|
/// </summary>
|
||||||
|
public readonly long EndId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据集
|
||||||
|
/// </summary>
|
||||||
|
public readonly IGachaLogDbService GachaLogDbService;
|
||||||
|
|
||||||
|
public GachaItemSaveContext(List<GachaItem> itemsToAdd, bool isLazy, GachaConfigType queryType, long endId, IGachaLogDbService gachaLogDbService)
|
||||||
|
{
|
||||||
|
ItemsToAdd = itemsToAdd;
|
||||||
|
IsLazy = isLazy;
|
||||||
|
QueryType = queryType;
|
||||||
|
EndId = endId;
|
||||||
|
GachaLogDbService = gachaLogDbService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveItems(GachaArchive archive)
|
||||||
|
{
|
||||||
|
if (ItemsToAdd.Count > 0)
|
||||||
|
{
|
||||||
|
// 全量刷新
|
||||||
|
if (!IsLazy)
|
||||||
|
{
|
||||||
|
GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId);
|
||||||
|
}
|
||||||
|
|
||||||
|
GachaLogDbService.AddGachaItemRange(ItemsToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,12 +14,11 @@ internal static class GachaLog
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询类型
|
/// 查询类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly FrozenSet<GachaType> QueryTypes = FrozenSet.ToFrozenSet(
|
public static readonly FrozenSet<GachaConfigType> QueryTypes = FrozenSet.ToFrozenSet(
|
||||||
[
|
[
|
||||||
GachaType.NewBie,
|
GachaConfigType.NoviceWish,
|
||||||
GachaType.Standard,
|
GachaConfigType.StandardWish,
|
||||||
GachaType.ActivityAvatar,
|
GachaConfigType.AvatarEventWish,
|
||||||
GachaType.ActivityWeapon,
|
GachaConfigType.WeaponEventWish,
|
||||||
GachaType.ActivityCity,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token)
|
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token)
|
||||||
{
|
{
|
||||||
GachaItem? item = null;
|
GachaItem? item = null;
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
return item?.Id ?? 0L;
|
return item?.Id ?? 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType)
|
public long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType)
|
||||||
{
|
{
|
||||||
GachaItem? item = null;
|
GachaItem? item = null;
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
return item?.Id ?? 0L;
|
return item?.Id ?? 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType)
|
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType)
|
||||||
{
|
{
|
||||||
GachaItem? item = null;
|
GachaItem? item = null;
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
return item?.Id ?? long.MaxValue;
|
return item?.Id ?? long.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType)
|
public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType)
|
||||||
{
|
{
|
||||||
GachaItem? item = null;
|
GachaItem? item = null;
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
return item?.Id ?? long.MaxValue;
|
return item?.Id ?? long.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token)
|
public async ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token)
|
||||||
{
|
{
|
||||||
GachaItem? item = null;
|
GachaItem? item = null;
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId)
|
public List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
@@ -291,7 +291,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId)
|
public async ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
@@ -368,7 +368,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId)
|
public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
@@ -381,7 +381,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId)
|
public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,14 +46,14 @@ internal struct GachaLogFetchContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前类型
|
/// 当前类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GachaType CurrentType;
|
public GachaConfigType CurrentType;
|
||||||
|
|
||||||
private readonly GachaLogServiceMetadataContext serviceContext;
|
private readonly GachaLogServiceMetadataContext serviceContext;
|
||||||
private readonly IGachaLogDbService gachaLogDbService;
|
private readonly IGachaLogDbService gachaLogDbService;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly bool isLazy;
|
private readonly bool isLazy;
|
||||||
|
|
||||||
public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, GachaLogServiceMetadataContext serviceContext, bool isLazy)
|
public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, in GachaLogServiceMetadataContext serviceContext, bool isLazy)
|
||||||
{
|
{
|
||||||
this.gachaLogDbService = gachaLogDbService;
|
this.gachaLogDbService = gachaLogDbService;
|
||||||
this.taskContext = taskContext;
|
this.taskContext = taskContext;
|
||||||
@@ -66,7 +66,7 @@ internal struct GachaLogFetchContext
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configType">卡池类型</param>
|
/// <param name="configType">卡池类型</param>
|
||||||
/// <param name="query">查询</param>
|
/// <param name="query">查询</param>
|
||||||
public void ResetForProcessingType(GachaType configType, in GachaLogQuery query)
|
public void ResetForProcessingType(GachaConfigType configType, in GachaLogQuery query)
|
||||||
{
|
{
|
||||||
DbEndId = null;
|
DbEndId = null;
|
||||||
CurrentType = configType;
|
CurrentType = configType;
|
||||||
@@ -140,18 +140,8 @@ internal struct GachaLogFetchContext
|
|||||||
// While no item is fetched, archive can be null.
|
// While no item is fetched, archive can be null.
|
||||||
if (TargetArchive is not null)
|
if (TargetArchive is not null)
|
||||||
{
|
{
|
||||||
if (ItemsToAdd.Count <= 0)
|
GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.Type, QueryOptions.EndId, gachaLogDbService);
|
||||||
{
|
saveContext.SaveItems(TargetArchive);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全量刷新
|
|
||||||
if (!isLazy)
|
|
||||||
{
|
|
||||||
gachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(TargetArchive.InnerId, QueryOptions.Type, QueryOptions.EndId);
|
|
||||||
}
|
|
||||||
|
|
||||||
gachaLogDbService.AddGachaItemRange(ItemsToAdd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,33 @@ using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
|||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 祈愿记录获取状态
|
||||||
|
/// </summary>
|
||||||
internal sealed class GachaLogFetchStatus
|
internal sealed class GachaLogFetchStatus
|
||||||
{
|
{
|
||||||
public GachaLogFetchStatus(GachaType configType)
|
/// <summary>
|
||||||
|
/// 构造一个新的祈愿记录获取状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configType">卡池类型</param>
|
||||||
|
public GachaLogFetchStatus(GachaConfigType configType)
|
||||||
{
|
{
|
||||||
ConfigType = configType;
|
ConfigType = configType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证密钥是否过期
|
||||||
|
/// </summary>
|
||||||
public bool AuthKeyTimeout { get; set; }
|
public bool AuthKeyTimeout { get; set; }
|
||||||
|
|
||||||
public GachaType ConfigType { get; set; }
|
/// <summary>
|
||||||
|
/// 卡池类型
|
||||||
|
/// </summary>
|
||||||
|
public GachaConfigType ConfigType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前获取的物品
|
||||||
|
/// </summary>
|
||||||
public List<Item> Items { get; set; } = new(20);
|
public List<Item> Items { get; set; } = new(20);
|
||||||
|
|
||||||
public string Header
|
public string Header
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Snap.Hutao.Model.Metadata.Weapon;
|
|||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.GachaLog.Factory;
|
using Snap.Hutao.Service.GachaLog.Factory;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
@@ -41,7 +40,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
if (await GetEndIdsFromCloudAsync(uid, token).ConfigureAwait(false) is { } endIds)
|
if (await GetEndIdsFromCloudAsync(uid, token).ConfigureAwait(false) is { } endIds)
|
||||||
{
|
{
|
||||||
List<Web.Hutao.GachaLog.GachaItem> items = [];
|
List<Web.Hutao.GachaLog.GachaItem> items = [];
|
||||||
foreach ((GachaType type, long endId) in endIds)
|
foreach ((GachaConfigType type, long endId) in endIds)
|
||||||
{
|
{
|
||||||
List<Web.Hutao.GachaLog.GachaItem> part = await gachaLogDbService
|
List<Web.Hutao.GachaLog.GachaItem> part = await gachaLogDbService
|
||||||
.GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId)
|
.GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId)
|
||||||
@@ -56,16 +55,14 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default)
|
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
GachaArchive? archive = await gachaLogDbService
|
GachaArchive? archive = await gachaLogDbService
|
||||||
.GetGachaArchiveByUidAsync(uid, token)
|
.GetGachaArchiveByUidAsync(uid, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false);
|
EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false);
|
||||||
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient
|
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false);
|
||||||
.RetrieveGachaItemsAsync(uid, endIds, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!resp.IsOk())
|
if (!resp.IsOk())
|
||||||
{
|
{
|
||||||
@@ -78,8 +75,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false);
|
await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Guid archiveId = archive.InnerId;
|
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archive.InnerId, i));
|
||||||
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i));
|
|
||||||
await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false);
|
await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false);
|
||||||
return new(true, archive.InnerId);
|
return new(true, archive.InnerId);
|
||||||
}
|
}
|
||||||
@@ -98,9 +94,10 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
HutaoStatisticsFactoryMetadataContext context = await metadataService
|
Dictionary<AvatarId, Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
||||||
.GetContextAsync<HutaoStatisticsFactoryMetadataContext>(token)
|
Dictionary<WeaponId, Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventListAsync(token).ConfigureAwait(false);
|
||||||
|
HutaoStatisticsFactoryMetadataContext context = new(idAvatarMap, idWeaponMap, gachaEvents);
|
||||||
|
|
||||||
GachaEventStatistics raw = response.Data;
|
GachaEventStatistics raw = response.Data;
|
||||||
try
|
try
|
||||||
@@ -129,7 +126,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
private async ValueTask<EndIds> CreateEndIdsAsync(GachaArchive? archive, CancellationToken token)
|
private async ValueTask<EndIds> CreateEndIdsAsync(GachaArchive? archive, CancellationToken token)
|
||||||
{
|
{
|
||||||
EndIds endIds = new();
|
EndIds endIds = new();
|
||||||
foreach (GachaType type in GachaLog.QueryTypes)
|
foreach (GachaConfigType type in GachaLog.QueryTypes)
|
||||||
{
|
{
|
||||||
if (archive is not null)
|
if (archive is not null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Snap.Hutao.Model.Primitive;
|
|||||||
using Snap.Hutao.Service.GachaLog.Factory;
|
using Snap.Hutao.Service.GachaLog.Factory;
|
||||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
@@ -56,14 +55,20 @@ internal sealed partial class GachaLogService : IGachaLogService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<bool> InitializeAsync(CancellationToken token = default)
|
public async ValueTask<bool> InitializeAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (context is { IsInitialized: true })
|
if (context.IsInitialized)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
context = await metadataService.GetContextAsync<GachaLogServiceMetadataContext>(token).ConfigureAwait(false);
|
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
||||||
|
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Dictionary<string, Model.Metadata.Avatar.Avatar> nameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false);
|
||||||
|
Dictionary<string, Model.Metadata.Weapon.Weapon> nameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false);
|
||||||
|
context = new(idAvatarMap, idWeaponMap, nameAvatarMap, nameWeaponMap);
|
||||||
|
|
||||||
ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection();
|
ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -177,7 +182,7 @@ internal sealed partial class GachaLogService : IGachaLogService
|
|||||||
ArgumentNullException.ThrowIfNull(ArchiveCollection);
|
ArgumentNullException.ThrowIfNull(ArchiveCollection);
|
||||||
GachaLogFetchContext fetchContext = new(gachaLogDbService, taskContext, context, isLazy);
|
GachaLogFetchContext fetchContext = new(gachaLogDbService, taskContext, context, isLazy);
|
||||||
|
|
||||||
foreach (GachaType configType in GachaLog.QueryTypes)
|
foreach (GachaConfigType configType in GachaLog.QueryTypes)
|
||||||
{
|
{
|
||||||
fetchContext.ResetForProcessingType(configType, query);
|
fetchContext.ResetForProcessingType(configType, query);
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,10 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Model.Metadata;
|
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
@@ -15,28 +13,65 @@ namespace Snap.Hutao.Service.GachaLog;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿记录服务上下文
|
/// 祈愿记录服务上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
internal readonly struct GachaLogServiceMetadataContext
|
||||||
IMetadataSupportInitialization,
|
|
||||||
IMetadataListGachaEventSource,
|
|
||||||
IMetadataDictionaryIdAvatarSource,
|
|
||||||
IMetadataDictionaryIdWeaponSource,
|
|
||||||
IMetadataDictionaryNameAvatarSource,
|
|
||||||
IMetadataDictionaryNameWeaponSource
|
|
||||||
{
|
{
|
||||||
public Dictionary<string, Item> ItemCache { get; set; } = [];
|
/// <summary>
|
||||||
|
/// 物品缓存
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<string, Item> ItemCache = [];
|
||||||
|
|
||||||
public List<GachaEvent> GachaEvents { get; set; } = default!;
|
/// <summary>
|
||||||
|
/// Id 角色 映射
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<AvatarId, Avatar> IdAvatarMap;
|
||||||
|
|
||||||
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
/// <summary>
|
||||||
|
/// Id 武器 映射
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<WeaponId, Weapon> IdWeaponMap;
|
||||||
|
|
||||||
public Dictionary<WeaponId, Weapon> IdWeaponMap { get; set; } = default!;
|
/// <summary>
|
||||||
|
/// 名称 角色 映射
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<string, Avatar> NameAvatarMap;
|
||||||
|
|
||||||
public Dictionary<string, Avatar> NameAvatarMap { get; set; } = default!;
|
/// <summary>
|
||||||
|
/// 名称 武器 映射
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<string, Weapon> NameWeaponMap;
|
||||||
|
|
||||||
public Dictionary<string, Weapon> NameWeaponMap { get; set; } = default!;
|
/// <summary>
|
||||||
|
/// 是否初始化完成
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsInitialized;
|
||||||
|
|
||||||
public bool IsInitialized { get; set; }
|
/// <summary>
|
||||||
|
/// 构造一个新的祈愿记录服务上下文
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idAvatarMap">Id 角色 映射</param>
|
||||||
|
/// <param name="idWeaponMap">Id 武器 映射</param>
|
||||||
|
/// <param name="nameAvatarMap">名称 角色 映射</param>
|
||||||
|
/// <param name="nameWeaponMap">名称 武器 映射</param>
|
||||||
|
public GachaLogServiceMetadataContext(
|
||||||
|
Dictionary<AvatarId, Avatar> idAvatarMap,
|
||||||
|
Dictionary<WeaponId, Weapon> idWeaponMap,
|
||||||
|
Dictionary<string, Avatar> nameAvatarMap,
|
||||||
|
Dictionary<string, Weapon> nameWeaponMap)
|
||||||
|
{
|
||||||
|
IdAvatarMap = idAvatarMap;
|
||||||
|
IdWeaponMap = idWeaponMap;
|
||||||
|
NameAvatarMap = nameAvatarMap;
|
||||||
|
NameWeaponMap = nameWeaponMap;
|
||||||
|
|
||||||
|
IsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按名称获取物品
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">名称</param>
|
||||||
|
/// <param name="type">类型</param>
|
||||||
|
/// <returns>物品</returns>
|
||||||
public Item GetItemByNameAndType(string name, string type)
|
public Item GetItemByNameAndType(string name, string type)
|
||||||
{
|
{
|
||||||
if (!ItemCache.TryGetValue(name, out Item? result))
|
if (!ItemCache.TryGetValue(name, out Item? result))
|
||||||
@@ -58,6 +93,11 @@ internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按物品 Id 获取名称星级
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Id</param>
|
||||||
|
/// <returns>名称星级</returns>
|
||||||
public INameQuality GetNameQualityByItemId(uint id)
|
public INameQuality GetNameQualityByItemId(uint id)
|
||||||
{
|
{
|
||||||
uint place = id.StringLength();
|
uint place = id.StringLength();
|
||||||
@@ -69,6 +109,12 @@ internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取物品 Id
|
||||||
|
/// O(1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">祈愿物品</param>
|
||||||
|
/// <returns>物品 Id</returns>
|
||||||
public uint GetItemId(GachaLogItem item)
|
public uint GetItemId(GachaLogItem item)
|
||||||
{
|
{
|
||||||
if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar)
|
if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal interface IGachaLogDbService
|
|||||||
|
|
||||||
ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId);
|
ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId);
|
||||||
|
|
||||||
void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId);
|
void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId);
|
||||||
|
|
||||||
ValueTask<GachaArchive?> GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token);
|
ValueTask<GachaArchive?> GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token);
|
||||||
|
|
||||||
@@ -31,25 +31,25 @@ internal interface IGachaLogDbService
|
|||||||
|
|
||||||
ValueTask<List<GachaItem>> GetGachaItemListByArchiveIdAsync(Guid archiveId);
|
ValueTask<List<GachaItem>> GetGachaItemListByArchiveIdAsync(Guid archiveId);
|
||||||
|
|
||||||
List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId);
|
List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId);
|
||||||
|
|
||||||
long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType);
|
long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
|
||||||
|
|
||||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token);
|
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||||
|
|
||||||
long GetOldestGachaItemIdByArchiveId(Guid archiveId);
|
long GetOldestGachaItemIdByArchiveId(Guid archiveId);
|
||||||
|
|
||||||
long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType);
|
long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
|
||||||
|
|
||||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token);
|
ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||||
|
|
||||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType);
|
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType);
|
||||||
|
|
||||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId);
|
ValueTask<long> GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId);
|
||||||
|
|
||||||
ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId);
|
ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||||
|
|
||||||
ValueTask AddGachaItemRangeAsync(List<GachaItem> items);
|
ValueTask AddGachaItemRangeAsync(List<GachaItem> items);
|
||||||
|
|
||||||
ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId);
|
ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ internal interface IGachaLogHutaoCloudService
|
|||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>是否获取成功</returns>
|
/// <returns>是否获取成功</returns>
|
||||||
ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default);
|
ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步上传祈愿记录
|
/// 异步上传祈愿记录
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
|||||||
Guid archiveId = archive.InnerId;
|
Guid archiveId = archive.InnerId;
|
||||||
|
|
||||||
List<GachaItem> fullItems = [];
|
List<GachaItem> fullItems = [];
|
||||||
foreach (GachaType queryType in GachaLog.QueryTypes)
|
foreach (GachaConfigType queryType in GachaLog.QueryTypes)
|
||||||
{
|
{
|
||||||
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType);
|
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType);
|
||||||
logger.LogInformation("Last Id to trim with: [{Id}]", trimId);
|
logger.LogInformation("Last Id to trim with: [{Id}]", trimId);
|
||||||
|
|||||||
@@ -23,15 +23,8 @@ internal sealed class LaunchExecutionBetterGenshinImpactAutomationHandlder : ILa
|
|||||||
Uri betterGenshinImpactUri = "bettergi://start".ToUri();
|
Uri betterGenshinImpactUri = "bettergi://start".ToUri();
|
||||||
if (await Launcher.QueryUriSupportAsync(betterGenshinImpactUri, LaunchQuerySupportType.Uri) is LaunchQuerySupportStatus.Available)
|
if (await Launcher.QueryUriSupportAsync(betterGenshinImpactUri, LaunchQuerySupportType.Uri) is LaunchQuerySupportStatus.Available)
|
||||||
{
|
{
|
||||||
try
|
context.Logger.LogInformation("Waiting game window to be ready");
|
||||||
{
|
context.Process.WaitForInputIdle();
|
||||||
context.Logger.LogInformation("Waiting game window to be ready");
|
|
||||||
context.Process.WaitForInputIdle();
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Logger.LogInformation("Launching BetterGI");
|
context.Logger.LogInformation("Launching BetterGI");
|
||||||
await Launcher.LaunchUriAsync(betterGenshinImpactUri);
|
await Launcher.LaunchUriAsync(betterGenshinImpactUri);
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
|
|
||||||
internal interface IMetadataDictionaryNameAvatarSource
|
|
||||||
{
|
|
||||||
public Dictionary<string, Model.Metadata.Avatar.Avatar> NameAvatarMap { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
|
|
||||||
internal interface IMetadataDictionaryNameWeaponSource
|
|
||||||
{
|
|
||||||
public Dictionary<string, Model.Metadata.Weapon.Weapon> NameWeaponMap { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Metadata;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
|
|
||||||
internal interface IMetadataListGachaEventSource
|
|
||||||
{
|
|
||||||
public List<GachaEvent> GachaEvents { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
|
|
||||||
|
|
||||||
internal interface IMetadataSupportInitialization
|
|
||||||
{
|
|
||||||
bool IsInitialized { get; set; }
|
|
||||||
}
|
|
||||||
@@ -21,51 +21,31 @@ internal static class MetadataServiceContextExtension
|
|||||||
{
|
{
|
||||||
listMaterialSource.Materials = await metadataService.GetMaterialListAsync(token).ConfigureAwait(false);
|
listMaterialSource.Materials = await metadataService.GetMaterialListAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context is IMetadataListGachaEventSource listGachaEventSource)
|
|
||||||
{
|
|
||||||
listGachaEventSource.GachaEvents = await metadataService.GetGachaEventListAsync(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dictionary
|
// Dictionary
|
||||||
{
|
{
|
||||||
if (context is IMetadataDictionaryIdAvatarSource dictionaryIdAvatarSource)
|
if (context is IMetadataDictionaryIdAvatarSource dictionaryAvatarSource)
|
||||||
{
|
{
|
||||||
dictionaryIdAvatarSource.IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
dictionaryAvatarSource.IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context is IMetadataDictionaryIdMaterialSource dictionaryIdMaterialSource)
|
if (context is IMetadataDictionaryIdMaterialSource dictionaryMaterialSource)
|
||||||
{
|
{
|
||||||
dictionaryIdMaterialSource.IdMaterialMap = await metadataService.GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
dictionaryMaterialSource.IdMaterialMap = await metadataService.GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context is IMetadataDictionaryIdWeaponSource dictionaryIdWeaponSource)
|
if (context is IMetadataDictionaryIdWeaponSource dictionaryWeaponSource)
|
||||||
{
|
{
|
||||||
dictionaryIdWeaponSource.IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
dictionaryWeaponSource.IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context is IMetadataDictionaryNameAvatarSource dictionaryNameAvatarSource)
|
|
||||||
{
|
|
||||||
dictionaryNameAvatarSource.NameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context is IMetadataDictionaryNameWeaponSource dictionaryNameWeaponSource)
|
|
||||||
{
|
|
||||||
dictionaryNameWeaponSource.NameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context is IMetadataSupportInitialization supportInitialization)
|
|
||||||
{
|
|
||||||
supportInitialization.IsInitialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable SH002
|
#pragma warning disable SH002
|
||||||
public static IEnumerable<Material> EnumerateInventoryMaterial(this IMetadataListMaterialSource context)
|
public static IEnumerable<Material> EnumerateInventroyMaterial(this IMetadataListMaterialSource context)
|
||||||
{
|
{
|
||||||
return context.Materials.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id.Value);
|
return context.Materials.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id.Value);
|
||||||
}
|
}
|
||||||
@@ -75,11 +55,6 @@ internal static class MetadataServiceContextExtension
|
|||||||
return context.IdAvatarMap[id];
|
return context.IdAvatarMap[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Avatar GetAvatar(this IMetadataDictionaryNameAvatarSource context, string name)
|
|
||||||
{
|
|
||||||
return context.NameAvatarMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Material GetMaterial(this IMetadataDictionaryIdMaterialSource context, MaterialId id)
|
public static Material GetMaterial(this IMetadataDictionaryIdMaterialSource context, MaterialId id)
|
||||||
{
|
{
|
||||||
return context.IdMaterialMap[id];
|
return context.IdMaterialMap[id];
|
||||||
@@ -89,10 +64,5 @@ internal static class MetadataServiceContextExtension
|
|||||||
{
|
{
|
||||||
return context.IdWeaponMap[id];
|
return context.IdWeaponMap[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Weapon GetWeapon(this IMetadataDictionaryNameWeaponSource context, string name)
|
|
||||||
{
|
|
||||||
return context.NameWeaponMap[name];
|
|
||||||
}
|
|
||||||
#pragma warning restore SH002
|
#pragma warning restore SH002
|
||||||
}
|
}
|
||||||
@@ -296,6 +296,7 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Collections" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Collections" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.HeaderedControls" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.HeaderedControls" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.240109" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
||||||
@@ -315,8 +316,8 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240227000" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
|
||||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||||
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
||||||
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">
|
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Microsoft.Web.WebView2.Core;
|
|||||||
using Snap.Hutao.Control.Extension;
|
using Snap.Hutao.Control.Extension;
|
||||||
using Snap.Hutao.Control.Theme;
|
using Snap.Hutao.Control.Theme;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||||
using System.Collections.Frozen;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
@@ -30,17 +29,17 @@ internal sealed partial class AnnouncementContentViewer : UserControl
|
|||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
private static readonly FrozenDictionary<string, string> DarkLightReverts = FrozenDictionary.ToFrozenDictionary(
|
private static readonly Dictionary<string, string> DarkLightReverts = new()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create("color:rgba(0,0,0,1)", "color:rgba(255,255,255,1)"),
|
{ "color:rgba(0,0,0,1)", "color:rgba(255,255,255,1)" },
|
||||||
KeyValuePair.Create("color:rgba(17,17,17,1)", "color:rgba(238,238,238,1)"),
|
{ "color:rgba(17,17,17,1)", "color:rgba(238,238,238,1)" },
|
||||||
KeyValuePair.Create("color:rgba(51,51,51,1)", "color:rgba(204,204,204,1)"),
|
{ "color:rgba(51,51,51,1)", "color:rgba(204,204,204,1)" },
|
||||||
KeyValuePair.Create("color:rgba(57,59,64,1)", "color:rgba(198,196,191,1)"),
|
{ "color:rgba(57,59,64,1)", "color:rgba(198,196,191,1)" },
|
||||||
KeyValuePair.Create("color:rgba(85,85,85,1)", "color:rgba(170,170,170,1)"),
|
{ "color:rgba(85,85,85,1)", "color:rgba(170,170,170,1)" },
|
||||||
KeyValuePair.Create("background-color: rgb(255, 215, 185)", "background-color: rgb(0,40,70)"),
|
{ "background-color: rgb(255, 215, 185)", "background-color: rgb(0,40,70)" },
|
||||||
KeyValuePair.Create("background-color: rgb(254, 245, 231)", "background-color: rgb(1,40,70)"),
|
{ "background-color: rgb(254, 245, 231)", "background-color: rgb(1,40,70)" },
|
||||||
KeyValuePair.Create("background-color:rgb(244, 244, 245)", "background-color:rgba(11, 11, 10)"),
|
{ "background-color:rgb(244, 244, 245)", "background-color:rgba(11, 11, 10)" },
|
||||||
]);
|
};
|
||||||
|
|
||||||
private readonly RoutedEventHandler loadEventHandler;
|
private readonly RoutedEventHandler loadEventHandler;
|
||||||
private readonly RoutedEventHandler unloadEventHandler;
|
private readonly RoutedEventHandler unloadEventHandler;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
@@ -26,11 +25,11 @@
|
|||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
x:Name="SkillSelectorSegmented"
|
x:Name="SkillSelectorSegmented"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
ItemTemplate="{StaticResource SkillHeaderTemplate}"
|
SelectionChanged="OnSkillSelectorSegmentedSelectionChanged"
|
||||||
SelectionChanged="OnSkillSelectorSegmentedSelectionChanged"/>
|
ItemTemplate="{StaticResource SkillHeaderTemplate}"/>
|
||||||
<ContentPresenter Content="{x:Bind Selected, Mode=OneWay}" ContentTemplate="{x:Bind ItemTemplate}"/>
|
<ContentPresenter Content="{x:Bind Selected, Mode=OneWay}" ContentTemplate="{x:Bind ItemTemplate}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Controls;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Control.Segmented;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Control;
|
namespace Snap.Hutao.View.Control;
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
x:Class="Snap.Hutao.View.Control.StatisticsSegmented"
|
x:Class="Snap.Hutao.View.Control.StatisticsSegmented"
|
||||||
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:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
Style="{StaticResource DefaultSegmentedStyle}"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewControlStatisticsSegmentedItemContentStatistics}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewControlStatisticsSegmentedItemContentStatistics}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewControlStatisticsSegmentedItemContentProportion}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewControlStatisticsSegmentedItemContentProportion}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
</shcs:Segmented>
|
</cwc:Segmented>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Controls;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Control.Segmented;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Control;
|
namespace Snap.Hutao.View.Control;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Control;
|
|
||||||
using Snap.Hutao.Core.Windowing;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Converter.Specialized;
|
|
||||||
|
|
||||||
internal sealed class BackdropTypeToOpacityConverter : ValueConverter<BackdropType, double>
|
|
||||||
{
|
|
||||||
public override double Convert(BackdropType from)
|
|
||||||
{
|
|
||||||
return from is BackdropType.None ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
xmlns:shvg="using:Snap.Hutao.ViewModel.Guide"
|
xmlns:shvg="using:Snap.Hutao.ViewModel.Guide"
|
||||||
d:DataContext="{d:DesignInstance shvg:GuideViewModel}"
|
d:DataContext="{d:DesignInstance shvg:GuideViewModel}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
@@ -189,15 +188,15 @@
|
|||||||
</cwc:SwitchPresenter>
|
</cwc:SwitchPresenter>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
Margin="16"
|
Margin="16"
|
||||||
IsHitTestVisible="False"
|
IsHitTestVisible="False"
|
||||||
SelectedIndex="{Binding State, Mode=TwoWay}">
|
SelectedIndex="{Binding State, Mode=TwoWay}">
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepLanguage}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepLanguage}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepDocument}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepDocument}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepEnvironment}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepEnvironment}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<shcs:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResource}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResource}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
</shcs:Segmented>
|
</cwc:Segmented>
|
||||||
<Button
|
<Button
|
||||||
Command="{Binding NextOrCompleteCommand}"
|
Command="{Binding NextOrCompleteCommand}"
|
||||||
Content="{Binding NextOrCompleteButtonText}"
|
Content="{Binding NextOrCompleteButtonText}"
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shv="using:Snap.Hutao.View"
|
xmlns:shv="using:Snap.Hutao.View"
|
||||||
xmlns:shvcs="using:Snap.Hutao.View.Converter.Specialized"
|
|
||||||
xmlns:shvh="using:Snap.Hutao.View.Helper"
|
xmlns:shvh="using:Snap.Hutao.View.Helper"
|
||||||
xmlns:shvm="using:Snap.Hutao.ViewModel"
|
xmlns:shvm="using:Snap.Hutao.ViewModel"
|
||||||
xmlns:shvp="using:Snap.Hutao.View.Page"
|
xmlns:shvp="using:Snap.Hutao.View.Page"
|
||||||
@@ -28,16 +27,9 @@
|
|||||||
<Thickness x:Key="NavigationViewContentGridBorderThickness">0,1,0,0</Thickness>
|
<Thickness x:Key="NavigationViewContentGridBorderThickness">0,1,0,0</Thickness>
|
||||||
<x:Double x:Key="NavigationViewItemOnLeftIconBoxHeight">24</x:Double>
|
<x:Double x:Key="NavigationViewItemOnLeftIconBoxHeight">24</x:Double>
|
||||||
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="Transparent"/>
|
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="Transparent"/>
|
||||||
<shvcs:BackdropTypeToOpacityConverter x:Key="BackdropTypeToOpacityConverter"/>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
<!-- Background="{ThemeResource SolidBackgroundFillColorBaseBrush}" -->
|
||||||
<Grid Transitions="{ThemeResource EntranceThemeTransitions}">
|
<Grid Transitions="{ThemeResource EntranceThemeTransitions}">
|
||||||
<Border Background="{ThemeResource SolidBackgroundFillColorBaseBrush}" Opacity="{Binding AppOptions.BackdropType, Converter={StaticResource BackdropTypeToOpacityConverter}, Mode=OneWay}">
|
|
||||||
<Border.OpacityTransition>
|
|
||||||
<ScalarTransition Duration="0:0:1"/>
|
|
||||||
</Border.OpacityTransition>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Image
|
<Image
|
||||||
x:Name="BackgroundImagePresenter"
|
x:Name="BackgroundImagePresenter"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Animations;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
|
using Snap.Hutao.Control.Animation;
|
||||||
|
using Snap.Hutao.Control.Theme;
|
||||||
|
using Snap.Hutao.Service.BackgroundImage;
|
||||||
using Snap.Hutao.Service.Navigation;
|
using Snap.Hutao.Service.Navigation;
|
||||||
using Snap.Hutao.View.Page;
|
using Snap.Hutao.View.Page;
|
||||||
using Snap.Hutao.ViewModel;
|
using Snap.Hutao.ViewModel;
|
||||||
|
|||||||
@@ -243,11 +243,6 @@
|
|||||||
PlaceholderText="{shcm:ResourceString Name=ViewPageAchievementSearchPlaceholder}"
|
PlaceholderText="{shcm:ResourceString Name=ViewPageAchievementSearchPlaceholder}"
|
||||||
QueryIcon="{shcm:FontIcon Glyph=}"
|
QueryIcon="{shcm:FontIcon Glyph=}"
|
||||||
Text="{Binding SearchText, Mode=TwoWay}">
|
Text="{Binding SearchText, Mode=TwoWay}">
|
||||||
<AutoSuggestBox.TextBoxStyle>
|
|
||||||
<Style BasedOn="{StaticResource AutoSuggestBoxTextBoxStyle}" TargetType="TextBox">
|
|
||||||
<Setter Property="IsSpellCheckEnabled" Value="False"/>
|
|
||||||
</Style>
|
|
||||||
</AutoSuggestBox.TextBoxStyle>
|
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
|
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
|
||||||
<mxic:InvokeCommandAction Command="{Binding SearchAchievementCommand}" CommandParameter="{Binding SearchText}"/>
|
<mxic:InvokeCommandAction Command="{Binding SearchAchievementCommand}" CommandParameter="{Binding SearchText}"/>
|
||||||
|
|||||||
@@ -484,7 +484,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="0" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="0" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent}"/>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="1" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent2}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="1" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent2}"/>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="2" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.WeaponEvent}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="2" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.WeaponWish}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,9 @@
|
|||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:shc="using:Snap.Hutao.Control"
|
xmlns:shc="using:Snap.Hutao.Control"
|
||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
||||||
xmlns:shcs="using:Snap.Hutao.Control.Segmented"
|
|
||||||
xmlns:shct="using:Snap.Hutao.Control.Text"
|
xmlns:shct="using:Snap.Hutao.Control.Text"
|
||||||
xmlns:shvcom="using:Snap.Hutao.ViewModel.Complex"
|
xmlns:shvcom="using:Snap.Hutao.ViewModel.Complex"
|
||||||
xmlns:shvcon="using:Snap.Hutao.View.Control"
|
xmlns:shvcon="using:Snap.Hutao.View.Control"
|
||||||
@@ -505,58 +503,42 @@
|
|||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
|
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<DataTemplate x:Key="AvatarViewTemplate" d:DataType="shvcom:AvatarView">
|
|
||||||
<shvcon:ItemIcon
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
shch:UIElementHelper.OpacityObject="{Binding Icon}"
|
|
||||||
Icon="{Binding Icon}"
|
|
||||||
Opacity="0"
|
|
||||||
Quality="{Binding Quality}"/>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate x:Key="TeamItemTemplate" d:DataType="shvcom:Team">
|
<DataTemplate x:Key="TeamItemTemplate" d:DataType="shvcom:Team">
|
||||||
<Border Style="{StaticResource BorderCardStyle}">
|
<Border Margin="0,0,16,8" Style="{StaticResource BorderCardStyle}">
|
||||||
<Grid>
|
<Grid Margin="6">
|
||||||
<Grid.RowDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<RowDefinition Height="auto"/>
|
<ColumnDefinition Width="184"/>
|
||||||
<RowDefinition Height="auto"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Viewbox Stretch="Uniform">
|
<ItemsControl
|
||||||
<ItemsControl
|
MinWidth="210"
|
||||||
Margin="4"
|
HorizontalAlignment="Left"
|
||||||
HorizontalAlignment="Left"
|
ItemsSource="{Binding}">
|
||||||
ItemTemplate="{StaticResource AvatarViewTemplate}"
|
<ItemsControl.ItemsPanel>
|
||||||
ItemsPanel="{ThemeResource HorizontalStackPanelSpacing4Template}"
|
<ItemsPanelTemplate>
|
||||||
ItemsSource="{Binding}"/>
|
<StackPanel Orientation="Horizontal" Spacing="6"/>
|
||||||
</Viewbox>
|
</ItemsPanelTemplate>
|
||||||
<Border
|
</ItemsControl.ItemsPanel>
|
||||||
Grid.Row="1"
|
<ItemsControl.ItemTemplate>
|
||||||
Background="{ThemeResource SolidBackgroundFillColorBaseBrush}"
|
<DataTemplate>
|
||||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
<shvcon:ItemIcon
|
||||||
BorderThickness="0,1,0,0"
|
Width="40"
|
||||||
CornerRadius="{ThemeResource ControlCornerRadiusBottom}"
|
Height="40"
|
||||||
Opacity="0.7"/>
|
Icon="{Binding Icon}"
|
||||||
<Grid Grid.Row="1">
|
Quality="{Binding Quality}"/>
|
||||||
<Grid.ColumnDefinitions>
|
</DataTemplate>
|
||||||
<ColumnDefinition Width="1*"/>
|
</ItemsControl.ItemTemplate>
|
||||||
<ColumnDefinition Width="auto"/>
|
</ItemsControl>
|
||||||
<ColumnDefinition Width="5*"/>
|
<Viewbox
|
||||||
</Grid.ColumnDefinitions>
|
Grid.Column="1"
|
||||||
|
Height="40"
|
||||||
|
Stretch="Uniform">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Column="0"
|
Margin="4,8"
|
||||||
Margin="4"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Rank}"/>
|
|
||||||
<AppBarSeparator Grid.Column="1" Margin="-64,-2"/>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="4"
|
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{Binding Rate}"/>
|
Text="{Binding Rate}"/>
|
||||||
</Grid>
|
</Viewbox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@@ -629,7 +611,7 @@
|
|||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
DisplayMemberPath="Floor"
|
DisplayMemberPath="Floor"
|
||||||
ItemsSource="{Binding AvatarUsageRanks}"
|
ItemsSource="{Binding AvatarUsageRanks}"
|
||||||
SelectedItem="{Binding SelectedAvatarUsageRank, Mode=TwoWay}"/>
|
SelectedItem="{Binding SelectedAvatarUsageRank, Mode=TwoWay}"/>
|
||||||
@@ -663,7 +645,7 @@
|
|||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
DisplayMemberPath="Floor"
|
DisplayMemberPath="Floor"
|
||||||
ItemsSource="{Binding AvatarAppearanceRanks}"
|
ItemsSource="{Binding AvatarAppearanceRanks}"
|
||||||
SelectedItem="{Binding SelectedAvatarAppearanceRank, Mode=TwoWay}"/>
|
SelectedItem="{Binding SelectedAvatarAppearanceRank, Mode=TwoWay}"/>
|
||||||
@@ -692,7 +674,7 @@
|
|||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<shcs:Segmented
|
<cwc:Segmented
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="16,16,0,16"
|
Margin="16,16,0,16"
|
||||||
DisplayMemberPath="Floor"
|
DisplayMemberPath="Floor"
|
||||||
@@ -708,59 +690,32 @@
|
|||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<cwc:HeaderedContentControl Grid.Column="0">
|
<ListView
|
||||||
<cwc:HeaderedContentControl.Header>
|
Grid.Column="0"
|
||||||
<Border Margin="0,0,16,0" Style="{ThemeResource BorderCardStyle}">
|
Padding="0,0,0,0"
|
||||||
<TextBlock
|
ItemContainerStyle="{ThemeResource NoneSelectionListViewItemStyle}"
|
||||||
Margin="0,8"
|
ItemTemplate="{StaticResource TeamItemTemplate}"
|
||||||
HorizontalAlignment="Center"
|
ItemsSource="{Binding Up}"
|
||||||
Text="{shcm:ResourceString Name=ViewPageSpiralAbyssTeamAppearanceUpHeader}"/>
|
SelectionMode="None">
|
||||||
</Border>
|
<ListView.ItemsPanel>
|
||||||
</cwc:HeaderedContentControl.Header>
|
<ItemsPanelTemplate>
|
||||||
<ListView
|
<shcp:UniformPanel MinItemWidth="240"/>
|
||||||
Padding="0"
|
</ItemsPanelTemplate>
|
||||||
ItemContainerStyle="{ThemeResource NoneSelectionListViewItemStyle}"
|
</ListView.ItemsPanel>
|
||||||
ItemTemplate="{StaticResource TeamItemTemplate}"
|
</ListView>
|
||||||
ItemsSource="{Binding Up}"
|
<ListView
|
||||||
SelectionMode="None">
|
Grid.Column="1"
|
||||||
<ListView.ItemsPanel>
|
Padding="0,0,0,0"
|
||||||
<ItemsPanelTemplate>
|
ItemContainerStyle="{ThemeResource NoneSelectionListViewItemStyle}"
|
||||||
<shcp:UniformPanel
|
ItemTemplate="{StaticResource TeamItemTemplate}"
|
||||||
Padding="0,0,16,0"
|
ItemsSource="{Binding Down}"
|
||||||
ColumnSpacing="6"
|
SelectionMode="None">
|
||||||
MinItemWidth="240"
|
<ListView.ItemsPanel>
|
||||||
RowSpacing="2"/>
|
<ItemsPanelTemplate>
|
||||||
</ItemsPanelTemplate>
|
<shcp:UniformPanel MinItemWidth="240"/>
|
||||||
</ListView.ItemsPanel>
|
</ItemsPanelTemplate>
|
||||||
</ListView>
|
</ListView.ItemsPanel>
|
||||||
</cwc:HeaderedContentControl>
|
</ListView>
|
||||||
|
|
||||||
<cwc:HeaderedContentControl Grid.Column="1">
|
|
||||||
<cwc:HeaderedContentControl.Header>
|
|
||||||
<Border Margin="0,0,16,0" Style="{ThemeResource BorderCardStyle}">
|
|
||||||
<TextBlock
|
|
||||||
Margin="0,8"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="{shcm:ResourceString Name=ViewPageSpiralAbyssTeamAppearanceDownHeader}"/>
|
|
||||||
</Border>
|
|
||||||
</cwc:HeaderedContentControl.Header>
|
|
||||||
<ListView
|
|
||||||
Padding="0"
|
|
||||||
ItemContainerStyle="{ThemeResource NoneSelectionListViewItemStyle}"
|
|
||||||
ItemTemplate="{StaticResource TeamItemTemplate}"
|
|
||||||
ItemsSource="{Binding Down}"
|
|
||||||
SelectionMode="None">
|
|
||||||
<ListView.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<shcp:UniformPanel
|
|
||||||
Padding="0,0,16,0"
|
|
||||||
ColumnSpacing="6"
|
|
||||||
MinItemWidth="240"
|
|
||||||
RowSpacing="2"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ListView.ItemsPanel>
|
|
||||||
</ListView>
|
|
||||||
</cwc:HeaderedContentControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:shc="using:Snap.Hutao.Control"
|
xmlns:shc="using:Snap.Hutao.Control"
|
||||||
xmlns:shca="using:Snap.Hutao.Control.AutoSuggestBox"
|
|
||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
@@ -73,45 +72,8 @@
|
|||||||
</shct:DescriptionTextBlock>
|
</shct:DescriptionTextBlock>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="TokenTemplate">
|
<DataTemplate x:Key="SuggestionTemplate">
|
||||||
<Grid>
|
<TextBlock VerticalAlignment="Center" Text="{Binding}"/>
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Rectangle
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="4"
|
|
||||||
Height="22"
|
|
||||||
Margin="0,0,8,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
RadiusX="2"
|
|
||||||
RadiusY="2"
|
|
||||||
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
|
||||||
<Rectangle.Fill>
|
|
||||||
<SolidColorBrush Color="{Binding Quality}"/>
|
|
||||||
</Rectangle.Fill>
|
|
||||||
</Rectangle>
|
|
||||||
<shci:MonoChrome
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="22"
|
|
||||||
Height="22"
|
|
||||||
Margin="0,0,4,0"
|
|
||||||
Source="{Binding IconUri, Mode=OneWay}"
|
|
||||||
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
|
||||||
<shci:CachedImage
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="22"
|
|
||||||
Height="22"
|
|
||||||
Margin="-4,-2,8,2"
|
|
||||||
Source="{Binding SideIconUri, Mode=OneWay}"
|
|
||||||
Visibility="{Binding SideIconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Value}"/>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="AvatarListTemplate">
|
<DataTemplate x:Key="AvatarListTemplate">
|
||||||
@@ -304,33 +266,22 @@
|
|||||||
Margin="8,8,0,0"
|
Margin="8,8,0,0"
|
||||||
LocalSettingKeySuffixForCurrent="WikiAvatarPage.Avatars"/>
|
LocalSettingKeySuffixForCurrent="WikiAvatarPage.Avatars"/>
|
||||||
</CommandBar.Content>
|
</CommandBar.Content>
|
||||||
|
<!--<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="搜索提示"/>-->
|
||||||
<AppBarElementContainer>
|
<AppBarElementContainer>
|
||||||
<shca:AutoSuggestTokenBox
|
<cwc:TokenizingTextBox
|
||||||
Width="600"
|
x:Name="AvatarSuggestBox"
|
||||||
Height="44"
|
Width="520"
|
||||||
Margin="6,-2,6,6"
|
Margin="6,0,6,0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
AvailableTokens="{Binding AvailableTokens}"
|
|
||||||
FilterCommand="{Binding FilterCommand}"
|
|
||||||
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
|
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
|
||||||
MaximumTokens="5"
|
MaximumTokens="5"
|
||||||
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiAvatarAutoSuggestBoxPlaceHolder}"
|
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiAvatarAutoSuggestBoxPlaceHolder}"
|
||||||
QueryIcon="{cw:FontIconSource Glyph=}"
|
QueryIcon="{cw:FontIconSource Glyph=}"
|
||||||
Style="{StaticResource DefaultTokenizingTextBoxStyle}"
|
SuggestedItemTemplate="{StaticResource SuggestionTemplate}"
|
||||||
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
SuggestedItemsSource="{Binding AvailableQueries}"
|
||||||
SuggestedItemsSource="{Binding AvailableTokens.Values}"
|
|
||||||
Text="{Binding FilterToken, Mode=TwoWay}"
|
Text="{Binding FilterToken, Mode=TwoWay}"
|
||||||
TokenItemTemplate="{StaticResource TokenTemplate}">
|
TokenItemTemplate="{StaticResource SuggestionTemplate}"/>
|
||||||
<shca:AutoSuggestTokenBox.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<cwc:WrapPanel
|
|
||||||
cw:FrameworkElementExtensions.AncestorType="shca:AutoSuggestTokenBox"
|
|
||||||
HorizontalSpacing="2"
|
|
||||||
StretchChild="Last"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</shca:AutoSuggestTokenBox.ItemsPanel>
|
|
||||||
</shca:AutoSuggestTokenBox>
|
|
||||||
</AppBarElementContainer>
|
</AppBarElementContainer>
|
||||||
<AppBarButton
|
<AppBarButton
|
||||||
Command="{Binding CultivateCommand}"
|
Command="{Binding CultivateCommand}"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.ViewModel.Wiki;
|
using Snap.Hutao.ViewModel.Wiki;
|
||||||
|
|
||||||
@@ -17,7 +19,19 @@ internal sealed partial class WikiAvatarPage : ScopedPage
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public WikiAvatarPage()
|
public WikiAvatarPage()
|
||||||
{
|
{
|
||||||
InitializeWith<WikiAvatarViewModel>();
|
WikiAvatarViewModel viewModel = InitializeWith<WikiAvatarViewModel>();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
viewModel.Initialize(new TokenizingTextBoxAccessor(AvatarSuggestBox));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TokenizingTextBoxAccessor : ITokenizingTextBoxAccessor
|
||||||
|
{
|
||||||
|
public TokenizingTextBoxAccessor(TokenizingTextBox tokenizingTextBox)
|
||||||
|
{
|
||||||
|
TokenizingTextBox = tokenizingTextBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenizingTextBox TokenizingTextBox { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
||||||
xmlns:shc="using:Snap.Hutao.Control"
|
xmlns:shc="using:Snap.Hutao.Control"
|
||||||
xmlns:shca="using:Snap.Hutao.Control.AutoSuggestBox"
|
|
||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
@@ -33,45 +32,8 @@
|
|||||||
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="TokenTemplate">
|
<DataTemplate x:Key="SuggestionTemplate">
|
||||||
<Grid VerticalAlignment="Center">
|
<TextBlock VerticalAlignment="Center" Text="{Binding}"/>
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Rectangle
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="4"
|
|
||||||
Height="22"
|
|
||||||
Margin="0,0,8,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
RadiusX="2"
|
|
||||||
RadiusY="2"
|
|
||||||
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
|
||||||
<Rectangle.Fill>
|
|
||||||
<SolidColorBrush Color="{Binding Quality}"/>
|
|
||||||
</Rectangle.Fill>
|
|
||||||
</Rectangle>
|
|
||||||
<shci:MonoChrome
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="22"
|
|
||||||
Height="22"
|
|
||||||
Margin="0,0,4,0"
|
|
||||||
Source="{Binding IconUri, Mode=OneWay}"
|
|
||||||
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
|
||||||
<shci:CachedImage
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="22"
|
|
||||||
Height="22"
|
|
||||||
Margin="0,0,4,0"
|
|
||||||
Source="{Binding SideIconUri, Mode=OneWay}"
|
|
||||||
Visibility="{Binding SideIconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Value}"/>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="WeaponListTemplate">
|
<DataTemplate x:Key="WeaponListTemplate">
|
||||||
@@ -173,32 +135,21 @@
|
|||||||
LocalSettingKeySuffixForCurrent="WikiWeaponPage.Weapons"/>
|
LocalSettingKeySuffixForCurrent="WikiWeaponPage.Weapons"/>
|
||||||
</CommandBar.Content>
|
</CommandBar.Content>
|
||||||
<AppBarElementContainer>
|
<AppBarElementContainer>
|
||||||
<shca:AutoSuggestTokenBox
|
<cwc:TokenizingTextBox
|
||||||
x:Name="WeaponSuggestBox"
|
x:Name="WeaponSuggestBox"
|
||||||
Width="600"
|
Width="520"
|
||||||
Height="44"
|
Margin="16,0,6,0"
|
||||||
Margin="6,-2,6,6"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
AvailableTokens="{Binding AvailableTokens}"
|
ItemTemplate="{StaticResource SuggestionTemplate}"
|
||||||
FilterCommand="{Binding FilterCommand}"
|
|
||||||
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
|
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
|
||||||
MaximumTokens="5"
|
MaximumTokens="5"
|
||||||
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
|
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
|
||||||
QueryIcon="{cw:FontIconSource Glyph=}"
|
QueryIcon="{cw:FontIconSource Glyph=}"
|
||||||
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
SuggestedItemTemplate="{StaticResource SuggestionTemplate}"
|
||||||
SuggestedItemsSource="{Binding AvailableTokens.Values}"
|
SuggestedItemsSource="{Binding AvailableQueries}"
|
||||||
Text="{Binding FilterToken, Mode=TwoWay}"
|
Text="{Binding FilterToken, Mode=TwoWay}"
|
||||||
TokenItemTemplate="{StaticResource TokenTemplate}">
|
TokenItemTemplate="{StaticResource SuggestionTemplate}"/>
|
||||||
<shca:AutoSuggestTokenBox.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<cwc:WrapPanel
|
|
||||||
cw:FrameworkElementExtensions.AncestorType="shca:AutoSuggestTokenBox"
|
|
||||||
HorizontalSpacing="2"
|
|
||||||
StretchChild="Last"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</shca:AutoSuggestTokenBox.ItemsPanel>
|
|
||||||
</shca:AutoSuggestTokenBox>
|
|
||||||
</AppBarElementContainer>
|
</AppBarElementContainer>
|
||||||
<AppBarButton
|
<AppBarButton
|
||||||
Command="{Binding CultivateCommand}"
|
Command="{Binding CultivateCommand}"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 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 CommunityToolkit.WinUI.Controls;
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.ViewModel.Wiki;
|
using Snap.Hutao.ViewModel.Wiki;
|
||||||
|
|
||||||
@@ -17,7 +18,19 @@ internal sealed partial class WikiWeaponPage : ScopedPage
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public WikiWeaponPage()
|
public WikiWeaponPage()
|
||||||
{
|
{
|
||||||
InitializeWith<WikiWeaponViewModel>();
|
WikiWeaponViewModel viewModel = InitializeWith<WikiWeaponViewModel>();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
viewModel.Initialize(new TokenizingTextBoxAccessor(WeaponSuggestBox));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TokenizingTextBoxAccessor : ITokenizingTextBoxAccessor
|
||||||
|
{
|
||||||
|
public TokenizingTextBoxAccessor(TokenizingTextBox tokenizingTextBox)
|
||||||
|
{
|
||||||
|
TokenizingTextBox = tokenizingTextBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenizingTextBox TokenizingTextBox { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,27 +16,27 @@ namespace Snap.Hutao.ViewModel.AvatarProperty;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class AvatarProperty : ObservableObject, INameIcon, IAlternatingItem
|
internal sealed class AvatarProperty : ObservableObject, INameIcon, IAlternatingItem
|
||||||
{
|
{
|
||||||
private static readonly FrozenDictionary<FightProperty, Uri> PropertyIcons = FrozenDictionary.ToFrozenDictionary(
|
private static readonly FrozenDictionary<FightProperty, Uri> PropertyIcons = new Dictionary<FightProperty, Uri>()
|
||||||
[
|
{
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CDReduce.png").ToUri()),
|
[FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CDReduce.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_ChargeEfficiency.png").ToUri()),
|
[FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_ChargeEfficiency.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_CRITICAL, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Critical.png").ToUri()),
|
[FightProperty.FIGHT_PROP_CRITICAL] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Critical.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_CRITICAL_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Critical_Hurt.png").ToUri()),
|
[FightProperty.FIGHT_PROP_CRITICAL_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Critical_Hurt.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_CUR_ATTACK, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CurAttack.png").ToUri()),
|
[FightProperty.FIGHT_PROP_CUR_ATTACK] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CurAttack.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_CUR_DEFENSE, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CurDefense.png").ToUri()),
|
[FightProperty.FIGHT_PROP_CUR_DEFENSE] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_CurDefense.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_ELEMENT_MASTERY, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element.png").ToUri()),
|
[FightProperty.FIGHT_PROP_ELEMENT_MASTERY] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_ELEC_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Electric.png").ToUri()),
|
[FightProperty.FIGHT_PROP_ELEC_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Electric.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_FIRE_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Fire.png").ToUri()),
|
[FightProperty.FIGHT_PROP_FIRE_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Fire.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_GRASS_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Grass.png").ToUri()),
|
[FightProperty.FIGHT_PROP_GRASS_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Grass.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_ICE_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Ice.png").ToUri()),
|
[FightProperty.FIGHT_PROP_ICE_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Ice.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_ROCK_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Rock.png").ToUri()),
|
[FightProperty.FIGHT_PROP_ROCK_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Rock.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_WATER_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Water.png").ToUri()),
|
[FightProperty.FIGHT_PROP_WATER_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Water.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_WIND_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Wind.png").ToUri()),
|
[FightProperty.FIGHT_PROP_WIND_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Element_Wind.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_HEAL_ADD, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Heal.png").ToUri()),
|
[FightProperty.FIGHT_PROP_HEAL_ADD] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_Heal.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_MAX_HP, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_MaxHp.png").ToUri()),
|
[FightProperty.FIGHT_PROP_MAX_HP] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_MaxHp.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_PhysicalAttackUp.png").ToUri()),
|
[FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_PhysicalAttackUp.png").ToUri(),
|
||||||
KeyValuePair.Create(FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_ShieldCostMinus.png").ToUri()),
|
[FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO] = Web.HutaoEndpoints.StaticRaw("Property", "UI_Icon_ShieldCostMinus.png").ToUri(),
|
||||||
]);
|
}.ToFrozenDictionary();
|
||||||
|
|
||||||
private Brush? background;
|
private Brush? background;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Microsoft.Extensions.Primitives;
|
|||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Web.Hutao.SpiralAbyss;
|
using Snap.Hutao.Web.Hutao.SpiralAbyss;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.Complex;
|
namespace Snap.Hutao.ViewModel.Complex;
|
||||||
@@ -21,7 +20,7 @@ internal sealed class Team : List<AvatarView>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="team">队伍</param>
|
/// <param name="team">队伍</param>
|
||||||
/// <param name="idAvatarMap">映射</param>
|
/// <param name="idAvatarMap">映射</param>
|
||||||
public Team(ItemRate<string, int> team, Dictionary<AvatarId, Avatar> idAvatarMap, int rank)
|
public Team(ItemRate<string, int> team, Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||||
: base(4)
|
: base(4)
|
||||||
{
|
{
|
||||||
foreach (StringSegment item in new StringTokenizer(team.Item, [',']))
|
foreach (StringSegment item in new StringTokenizer(team.Item, [',']))
|
||||||
@@ -30,16 +29,11 @@ internal sealed class Team : List<AvatarView>
|
|||||||
Add(new(idAvatarMap[id]));
|
Add(new(idAvatarMap[id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
AddRange(new AvatarView[4 - Count]);
|
|
||||||
|
|
||||||
Rate = SH.FormatModelBindingHutaoTeamUpCountFormat(team.Rate);
|
Rate = SH.FormatModelBindingHutaoTeamUpCountFormat(team.Rate);
|
||||||
Rank = rank;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上场次数
|
/// 上场次数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Rate { get; }
|
public string Rate { get; }
|
||||||
|
|
||||||
public int Rank { get; set; }
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user