Compare commits

..

1 Commits

Author SHA1 Message Date
qhy040404
fe9078d486 prompt if hotkey not registered 2024-02-21 19:28:08 +08:00
157 changed files with 951 additions and 2356 deletions

View File

@@ -18,7 +18,7 @@ body:
options: options:
- label: 我已阅读 Snap Hutao 文档中的[常见问题](https://hut.ao/advanced/FAQ.html)和[常见程序异常](https://hut.ao/advanced/exceptions.html),我的问题没有在文档中得到解答 - label: 我已阅读 Snap Hutao 文档中的[常见问题](https://hut.ao/advanced/FAQ.html)和[常见程序异常](https://hut.ao/advanced/exceptions.html),我的问题没有在文档中得到解答
required: true required: true
- label: 我知道文档站的导航栏中有**搜索功能**,且已经搜索过相关关键词 - label: 我知道文档站的导航栏中有**搜索功能**,且已经搜索过相关关键词
required: true required: true
@@ -29,12 +29,12 @@ body:
id: winver id: winver
attributes: attributes:
label: Windows 版本 label: Windows 版本
description: | description: |
`Win+R` 输入 `winver` 回车后在打开的窗口第二行可以找到 `Win+R` 输入 `winver` 回车后在打开的窗口第二行可以找到
placeholder: 22000.556 placeholder: 22000.556
validations: validations:
required: true required: true
- type: input - type: input
id: shver id: shver
attributes: attributes:
@@ -48,10 +48,10 @@ body:
id: deviceid id: deviceid
attributes: attributes:
label: 设备 ID label: 设备 ID
description: | description: |
在胡桃工具箱的反馈中心界面,你可以找到并复制你的设备 ID 在胡桃工具箱的反馈中心界面,你可以找到并复制你的设备 ID
如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题 如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题
如果你的程序已经无法启动,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.Diagnostic.Tooling.exe),它将显示你的设备 ID 如果你的程序已经无法启动,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
validations: validations:
required: false required: false
@@ -79,7 +79,7 @@ body:
- 公告 - 公告
- 其它 - 其它
validations: validations:
required: true required: true
- type: textarea - type: textarea
id: what-happened id: what-happened
@@ -107,3 +107,4 @@ body:
options: options:
- label: 我认为上述的描述已经足以详细,以允许开发人员能复现该问题 - label: 我认为上述的描述已经足以详细,以允许开发人员能复现该问题
required: true required: true

View File

@@ -18,7 +18,7 @@ body:
options: options:
- label: I have read [FAQ page](https://hut.ao/advanced/FAQ.html) and [Exception page](https://hut.ao/advanced/exceptions.html) in Snap Hutao document, and my issue is not answered - label: I have read [FAQ page](https://hut.ao/advanced/FAQ.html) and [Exception page](https://hut.ao/advanced/exceptions.html) in Snap Hutao document, and my issue is not answered
required: true required: true
- label: I and tried **search feature** in Snap Hutao document site, and no associated article - label: I and tried **search feature** in Snap Hutao document site, and no associated article
required: true required: true
@@ -29,12 +29,12 @@ body:
id: winver id: winver
attributes: attributes:
label: Windows Version label: Windows Version
description: | description: |
Use `Win+R` and input `winver`, Windows build version is usually at the second line Use `Win+R` and input `winver`, Windows build version is usually at the second line
placeholder: e.g. 22000.556 placeholder: e.g. 22000.556
validations: validations:
required: true required: true
- type: input - type: input
id: shver id: shver
attributes: attributes:
@@ -48,10 +48,10 @@ body:
id: deviceid id: deviceid
attributes: attributes:
label: Device ID label: Device ID
description: | description: |
In Snap Hutao's Feedback Center, you can find and copy your device ID In Snap Hutao's Feedback Center, you can find and copy your device ID
If your issue is about program crash, please fill this so we can dump the log and locate the source easier If your issue is about program crash, please fill this so we can dump the log and locate the source easier
If your program cannot startup, please download and run [Diagnostic Tooling](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.Diagnostic.Tooling.exe), it will shows your device ID. If your program cannot startup, please download and run [Diagnosis Tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will shows your device ID.
validations: validations:
required: false required: false
@@ -74,12 +74,12 @@ body:
- User Interface - User Interface
- Snap Hutao Cloud - Snap Hutao Cloud
- Snap Hutao Account - Snap Hutao Account
- Checkin - Checkin
- Wiki - Wiki
- Announcement - Announcement
- Other - Other
validations: validations:
required: true required: true
- type: textarea - type: textarea
id: what-happened id: what-happened
@@ -107,3 +107,4 @@ body:
options: options:
- label: I believe the description above is detail enough to allow developers to reproduce the issue - label: I believe the description above is detail enough to allow developers to reproduce the issue
required: true required: true

View File

@@ -13,8 +13,4 @@ updates:
groups: groups:
packages: packages:
patterns: patterns:
- "*" - "*"
- package-ecosystem: "github-actions"
directory: "/.github/workflows" # GitHub Workflows
schedule:
interval: "weekly"

View File

@@ -31,10 +31,10 @@ jobs:
runs-on: self-hosted runs-on: self-hosted
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4.1.1
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4.0.0
with: with:
dotnet-version: 8.0 dotnet-version: 8.0

View File

@@ -74,4 +74,3 @@ Refresh:
script: script:
- apt-get install -y curl - apt-get install -y curl
- curl -X PATCH "$PURGE_URL" - curl -X PATCH "$PURGE_URL"
- curl -X POST -o /dev/null "$UPLOAD_OSS_URL"

View File

@@ -35,8 +35,7 @@ Install with Snap Hutao MSIX package, can be installed with Windows built-in App
* [向我们提交 PR / Make Pull Requests](https://github.com/DGP-Studio/Snap.Hutao/pulls) * [向我们提交 PR / Make Pull Requests](https://github.com/DGP-Studio/Snap.Hutao/pulls)
* [在 Crowdin 上进行本地化 / Translate Project on Crowdin](https://translate.hut.ao/) * [在 Crowdin 上进行本地化 / Translate Project on Crowdin](https://translate.hut.ao/)
* [为我们更新文档 / Enhance our Document](https://github.com/DGP-Studio/Snap.Hutao.Docs) * [为我们更新文档 / Enhance our Document ](https://github.com/DGP-Studio/Snap.Hutao.Docs)
* [帮助我们测试程序 / Test Binary Package](https://hut.ao/development/contribute.html)
## 特别感谢 / Special Thanks ## 特别感谢 / Special Thanks

View File

@@ -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>

View File

@@ -6,7 +6,6 @@
<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/Theme/Card.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
@@ -23,7 +22,6 @@
<ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/ScrollViewer.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/ScrollViewer.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/SegmentedOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Thickness.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/Thickness.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/> <ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>

View File

@@ -1,65 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml.Controls;
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);
}
}

View File

@@ -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;
}
}

View File

@@ -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,
}

View File

@@ -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;
}
} }
} }

View File

@@ -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()

View File

@@ -5,6 +5,7 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes; using Microsoft.UI.Xaml.Shapes;
using System.Collections.Specialized;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Snap.Hutao.Control.Brush; namespace Snap.Hutao.Control.Brush;

View File

@@ -4,6 +4,7 @@
using CommunityToolkit.WinUI.Collections; using CommunityToolkit.WinUI.Collections;
using CommunityToolkit.WinUI.Helpers; using CommunityToolkit.WinUI.Helpers;
using Microsoft.UI.Xaml.Data; using Microsoft.UI.Xaml.Data;
using Snap.Hutao.Core.ExceptionService;
using System.Collections; using System.Collections;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
@@ -207,11 +208,13 @@ internal sealed class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, IN
public void Add(T item) public void Add(T item)
{ {
ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only.");
source.Add(item); source.Add(item);
} }
public void Clear() public void Clear()
{ {
ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only.");
source.Clear(); source.Clear();
} }
@@ -227,6 +230,7 @@ internal sealed class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, IN
public bool Remove(T item) public bool Remove(T item)
{ {
ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only.");
source.Remove(item); source.Remove(item);
return true; return true;
} }
@@ -239,6 +243,7 @@ internal sealed class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, IN
public void Insert(int index, T item) public void Insert(int index, T item)
{ {
ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only.");
source.Insert(index, item); source.Insert(index, item);
} }

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -1,6 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control;
internal interface IXamlElementAccessor;

View File

@@ -168,7 +168,6 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
if (surface.DecodedPhysicalSize.Size() <= 0D) if (surface.DecodedPhysicalSize.Size() <= 0D)
{ {
await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true); await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true);
await Task.Delay(50, token).ConfigureAwait(true);
} }
LoadImageSurfaceCompleted(surface); LoadImageSurfaceCompleted(surface);

View File

@@ -1,89 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using System.Data;
using System.Runtime.InteropServices;
using Windows.Foundation;
namespace Snap.Hutao.Control.Panel;
[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;
List<UIElement> elements = [.. Children.Where(element => element.Visibility == Visibility.Visible)];
visibleItemsCount = elements.Count;
foreach (ref readonly UIElement child in CollectionsMarshal.AsSpan(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 is not 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)
{
(d as EqualPanel)?.InvalidateMeasure();
}
private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
{
InvalidateMeasure();
}
}

View File

@@ -6,7 +6,6 @@
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"
Style="{StaticResource DefaultSegmentedStyle}"
mc:Ignorable="d"> mc:Ignorable="d">
<cwc:SegmentedItem <cwc:SegmentedItem

View File

@@ -4,7 +4,6 @@
using CommunityToolkit.WinUI.Controls; using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Setting; using Snap.Hutao.Core.Setting;
using System.Collections.Frozen;
namespace Snap.Hutao.Control.Panel; namespace Snap.Hutao.Control.Panel;
@@ -20,11 +19,11 @@ 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;

View File

@@ -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>

View File

@@ -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);
} }

View File

@@ -1,115 +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:cwc="using:CommunityToolkit.WinUI.Controls"
xmlns:shcp="using:Snap.Hutao.Control.Panel"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/SegmentedItem/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="cwc:Segmented"/>
<Style x:Key="DefaultSegmentedStyle" TargetType="cwc: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>
<shcp:EqualPanel
HorizontalAlignment="{Binding (cw:FrameworkElementExtensions.Ancestor).HorizontalAlignment, RelativeSource={RelativeSource Self}}"
cw:FrameworkElementExtensions.AncestorType="cwc:Segmented"
Spacing="{ThemeResource SegmentedItemSpacing}"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cwc: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="cwc: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="cwc: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>

View File

@@ -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 Snap.Hutao.Core.DependencyInjection.Abstraction;
using Snap.Hutao.Core.IO; using Snap.Hutao.Core.IO;
namespace Snap.Hutao.Core.Caching; namespace Snap.Hutao.Core.Caching;
@@ -9,7 +10,7 @@ namespace Snap.Hutao.Core.Caching;
/// 为图像缓存提供抽象 /// 为图像缓存提供抽象
/// </summary> /// </summary>
[HighQuality] [HighQuality]
internal interface IImageCache internal interface IImageCache : ICastService
{ {
/// <summary> /// <summary>
/// Gets the file path containing cached item for given Uri /// Gets the file path containing cached item for given Uri

View File

@@ -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();

View File

@@ -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>();
}); });

View File

@@ -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")]

View File

@@ -37,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);
}
} }

View File

@@ -7,7 +7,4 @@ internal enum HutaoExceptionKind
{ {
None, None,
ServiceTypeCastFailed, ServiceTypeCastFailed,
FileSystemCreateFileInsufficientPermissions,
PrivateNamedPipeContentHashIncorrect,
GachaStatisticsInvalidItemId,
} }

View File

@@ -29,7 +29,7 @@ internal readonly struct TempFile : IDisposable
} }
catch (UnauthorizedAccessException ex) catch (UnauthorizedAccessException ex)
{ {
HutaoException.Throw(HutaoExceptionKind.FileSystemCreateFileInsufficientPermissions, SH.CoreIOTempFileCreateFail, ex); ThrowHelper.RuntimeEnvironment(SH.CoreIOTempFileCreateFail, ex);
} }
if (delete) if (delete)

View File

@@ -148,15 +148,17 @@ internal sealed partial class Activation : IActivation
await taskContext.SwitchToBackgroundAsync(); await taskContext.SwitchToBackgroundAsync();
if (serviceProvider.GetRequiredService<IMetadataService>() is IMetadataServiceInitialization metadataServiceInitialization) serviceProvider
{ .GetRequiredService<IMetadataService>()
metadataServiceInitialization.InitializeInternalAsync().SafeForget(); .As<IMetadataServiceInitialization>()?
} .InitializeInternalAsync()
.SafeForget();
if (serviceProvider.GetRequiredService<IHutaoUserService>() is IHutaoUserServiceInitialization hutaoUserServiceInitialization) serviceProvider
{ .GetRequiredService<IHutaoUserService>()
hutaoUserServiceInitialization.InitializeInternalAsync().SafeForget(); .As<IHutaoUserServiceInitialization>()?
} .InitializeInternalAsync()
.SafeForget();
serviceProvider serviceProvider
.GetRequiredService<IDiscordService>() .GetRequiredService<IDiscordService>()

View File

@@ -49,7 +49,7 @@ internal sealed partial class PrivateNamedPipeServer : IDisposable
{ {
byte[] content = new byte[header->ContentLength]; byte[] content = new byte[header->ContentLength];
serverStream.ReadAtLeast(content, header->ContentLength, false); serverStream.ReadAtLeast(content, header->ContentLength, false);
HutaoException.ThrowIf(XxHash64.HashToUInt64(content) != header->Checksum, HutaoExceptionKind.PrivateNamedPipeContentHashIncorrect, "PipePacket Content Hash incorrect"); ThrowHelper.InvalidDataIf(XxHash64.HashToUInt64(content) != header->Checksum, "PipePacket Content Hash incorrect");
return content; return content;
} }

View File

@@ -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>
/// 获取对象类型的显示名称 /// 获取对象类型的显示名称

View File

@@ -122,17 +122,13 @@ internal sealed class WindowController
private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e) private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
{ {
if (sender is not AppOptions options) if (e.PropertyName is nameof(AppOptions.BackdropType))
{ {
return; if (sender is AppOptions options)
{
UpdateSystemBackdrop(options.BackdropType);
}
} }
_ = e.PropertyName switch
{
nameof(AppOptions.BackdropType) => UpdateSystemBackdrop(options.BackdropType),
nameof(AppOptions.ElementTheme) => UpdateElementTheme(options.ElementTheme),
_ => false,
};
} }
private void OnWindowClosed(object sender, WindowEventArgs args) private void OnWindowClosed(object sender, WindowEventArgs args)
@@ -162,7 +158,7 @@ internal sealed class WindowController
} }
} }
private bool UpdateSystemBackdrop(BackdropType backdropType) private void UpdateSystemBackdrop(BackdropType backdropType)
{ {
window.SystemBackdrop = backdropType switch window.SystemBackdrop = backdropType switch
{ {
@@ -172,15 +168,6 @@ internal sealed class WindowController
BackdropType.Acrylic => new DesktopAcrylicBackdrop(), BackdropType.Acrylic => new DesktopAcrylicBackdrop(),
_ => null, _ => null,
}; };
return true;
}
private bool UpdateElementTheme(ElementTheme theme)
{
((FrameworkElement)window.Content).RequestedTheme = theme;
return true;
} }
private void UpdateTitleButtonColor() private void UpdateTitleButtonColor()

View File

@@ -18,11 +18,20 @@ internal static class DateTimeOffsetExtension
return defaultValue; return defaultValue;
} }
return value switch try
{ {
>= -62135596800 and <= 253402300799 => DateTimeOffset.FromUnixTimeSeconds(value), return DateTimeOffset.FromUnixTimeSeconds(value);
>= -62135596800000 and <= 253402300799999 => DateTimeOffset.FromUnixTimeMilliseconds(value), }
_ => defaultValue, catch (ArgumentOutOfRangeException)
}; {
try
{
return DateTimeOffset.FromUnixTimeMilliseconds(value);
}
catch (ArgumentOutOfRangeException)
{
return defaultValue;
}
}
} }
} }

View File

@@ -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();
@@ -52,6 +46,34 @@ internal static partial class EnumerableExtension
return first; return first;
} }
public static string JoinToString<T>(this IEnumerable<T> source, char separator, Action<StringBuilder, T> selector)
{
StringBuilder resultBuilder = new();
IEnumerator<T> enumerator = source.GetEnumerator();
if (!enumerator.MoveNext())
{
return string.Empty;
}
T first = enumerator.Current;
selector(resultBuilder, first);
if (!enumerator.MoveNext())
{
return resultBuilder.ToString();
}
do
{
resultBuilder.Append(separator);
selector(resultBuilder, enumerator.Current);
}
while (enumerator.MoveNext());
return resultBuilder.ToString();
}
public static string JoinToString<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, char separator, Action<StringBuilder, TKey, TValue> selector) public static string JoinToString<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, char separator, Action<StringBuilder, TKey, TValue> selector)
{ {
StringBuilder resultBuilder = new(); StringBuilder resultBuilder = new();

View File

@@ -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",

View File

@@ -27,7 +27,7 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IMinMax
public MainWindow(IServiceProvider serviceProvider) public MainWindow(IServiceProvider serviceProvider)
{ {
InitializeComponent(); InitializeComponent();
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), true); windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), true, false);
this.InitializeController(serviceProvider); this.InitializeController(serviceProvider);
} }

View File

@@ -1,6 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Message;
internal sealed class BackgroundImageTypeChangedMessage;

View File

@@ -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

View File

@@ -13,7 +13,6 @@ internal sealed partial class SettingEntry
public const string Culture = "Culture"; public const string Culture = "Culture";
public const string SystemBackdropType = "SystemBackdropType"; public const string SystemBackdropType = "SystemBackdropType";
public const string ElementTheme = "ElementTheme";
public const string BackgroundImageType = "BackgroundImageType"; public const string BackgroundImageType = "BackgroundImageType";
public const string AnnouncementRegion = "AnnouncementRegion"; public const string AnnouncementRegion = "AnnouncementRegion";

View File

@@ -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)
{ {

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -1,9 +1,22 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Achievement; 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; }
}

View File

@@ -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);
}
}

View File

@@ -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>
/// 将中文元素名称转换为图标链接 /// 将中文元素名称转换为图标链接

View File

@@ -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,
};
} }
} }

View File

@@ -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>

View File

@@ -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; }
}

View File

@@ -1,17 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
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!;
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
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!;
}

View File

@@ -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; }
}

View File

@@ -49,7 +49,7 @@ internal sealed class GachaEvent
/// <summary> /// <summary>
/// 卡池类型 /// 卡池类型
/// </summary> /// </summary>
public GachaType Type { get; set; } public GachaConfigType Type { get; set; }
/// <summary> /// <summary>
/// 五星列表 /// 五星列表

View File

@@ -1,19 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
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; }
}

View File

@@ -13,7 +13,7 @@
<Identity <Identity
Name="60568DGPStudio.SnapHutao" Name="60568DGPStudio.SnapHutao"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52" Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.9.7.0" /> Version="1.9.6.0" />
<Properties> <Properties>
<DisplayName>Snap Hutao</DisplayName> <DisplayName>Snap Hutao</DisplayName>

View File

@@ -13,7 +13,7 @@
<Identity <Identity
Name="60568DGPStudio.SnapHutaoDev" Name="60568DGPStudio.SnapHutaoDev"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52" Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.9.7.0" /> Version="1.9.6.0" />
<Properties> <Properties>
<DisplayName>Snap Hutao Dev</DisplayName> <DisplayName>Snap Hutao Dev</DisplayName>

View File

@@ -60,45 +60,45 @@
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"> <xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" /> <xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" /> <xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" /> <xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" /> <xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>
@@ -145,7 +145,7 @@
<value>Save</value> <value>Save</value>
</data> </data>
<data name="ControlImageCachedImageInvalidResourceUri" xml:space="preserve"> <data name="ControlImageCachedImageInvalidResourceUri" xml:space="preserve">
<value>Invalid Uri</value> <value>Invalid URL</value>
</data> </data>
<data name="ControlImageCompositionImageHttpRequest" xml:space="preserve"> <data name="ControlImageCompositionImageHttpRequest" xml:space="preserve">
<value>HTTP GET {0}</value> <value>HTTP GET {0}</value>
@@ -186,15 +186,6 @@
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve"> <data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
<value>No WebView2 Runtime detected</value> <value>No WebView2 Runtime detected</value>
</data> </data>
<data name="CoreWindowThemeDark" xml:space="preserve">
<value>Dark</value>
</data>
<data name="CoreWindowThemeLight" xml:space="preserve">
<value>Light</value>
</data>
<data name="CoreWindowThemeSystem" xml:space="preserve">
<value>System</value>
</data>
<data name="FilePickerExportCommit" xml:space="preserve"> <data name="FilePickerExportCommit" xml:space="preserve">
<value>Export</value> <value>Export</value>
</data> </data>
@@ -294,7 +285,7 @@
<comment>Need EXACT same string in game</comment> <comment>Need EXACT same string in game</comment>
</data> </data>
<data name="ModelIntrinsicAssociationTypeInazuma" xml:space="preserve"> <data name="ModelIntrinsicAssociationTypeInazuma" xml:space="preserve">
<value>Inazuma</value> <value>Inadzuma</value>
<comment>Need EXACT same string in game</comment> <comment>Need EXACT same string in game</comment>
</data> </data>
<data name="ModelIntrinsicAssociationTypeLiyue" xml:space="preserve"> <data name="ModelIntrinsicAssociationTypeLiyue" xml:space="preserve">
@@ -555,7 +546,7 @@
<value>Uploaded {1} wish records of UID: {0}, stored {2}</value> <value>Uploaded {1} wish records of UID: {0}, stored {2}</value>
</data> </data>
<data name="ServerPassportLoginRequired" xml:space="preserve"> <data name="ServerPassportLoginRequired" xml:space="preserve">
<value>Please login or register Snap Hutao account first</value> <value>Please login or register Hutao account first</value>
</data> </data>
<data name="ServerPassportLoginSucceed" xml:space="preserve"> <data name="ServerPassportLoginSucceed" xml:space="preserve">
<value>Login successfully</value> <value>Login successfully</value>
@@ -567,7 +558,7 @@
<value>Password has been set successfully</value> <value>Password has been set successfully</value>
</data> </data>
<data name="ServerPassportServiceEmailHasNotRegistered" xml:space="preserve"> <data name="ServerPassportServiceEmailHasNotRegistered" xml:space="preserve">
<value>Current email address is not registered</value> <value>Current email adress is not registered</value>
</data> </data>
<data name="ServerPassportServiceEmailHasRegistered" xml:space="preserve"> <data name="ServerPassportServiceEmailHasRegistered" xml:space="preserve">
<value>Current emaill address is registered</value> <value>Current emaill address is registered</value>
@@ -776,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>Character Showcase: {0:MM-dd HH:mm}</value> <value>Character Showcase: {0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>Bing Daily Wallpaper</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>Hutao Daily Wallpaper</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>Genshin Official Launcher Wallpaper</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>Local Random Image</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>No Wallpaper</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>Failed to save development plan status</value> <value>Failed to save development plan status</value>
</data> </data>
@@ -848,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>Parametric Transformer is ready</value> <value>Parametric Transformer is ready</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>Missing permission, unable to set your Discord Activity.</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>Exploring in Teyvat</value> <value>Exploring in Teyvat</value>
</data> </data>
@@ -1418,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>Game Launcher</value> <value>Game Launcher</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>Cannot reorder in Admin Mode</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>Archive [{0}] added successfully</value> <value>Archive [{0}] added successfully</value>
</data> </data>
@@ -1700,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>Completed</value> <value>Completed</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>Response stream does not contain valid content type</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>Queued</value> <value>Queued</value>
</data> </data>
@@ -2219,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>Launch Parameters</value> <value>Launch Parameters</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>Auto start Better GUI for automation tasks after game launched</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>General</value> <value>General</value>
</data> </data>
@@ -2366,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>Backdrop Material</value> <value>Backdrop Material</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>Image Copyright Information</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>Change the source of wallpaper, restart Snap Hutao to apply the change</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>Wallpaper Image</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>Images cache are saved here</value> <value>Images cache are saved here</value>
</data> </data>
@@ -2592,10 +2544,10 @@
<value>Reset Image Resource</value> <value>Reset Image Resource</value>
</data> </data>
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve"> <data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
<value>Add Unlock Frame Rate Limit Option in Game Launcher Process Section</value> <value>在启动游戏页面的进程部分加入解锁帧率限制选项</value>
</data> </data>
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve"> <data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
<value>Game Launcher - Unlock Frame Rate Limit</value> <value>启动游戏-解锁帧率限制</value>
</data> </data>
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve"> <data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
<value>You need to move data in the directory manually, otherwise new user data will be created.</value> <value>You need to move data in the directory manually, otherwise new user data will be created.</value>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>Pameran Karakter: {0:MM-dd HH:mm}</value> <value>Pameran Karakter: {0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>Gagal menyimpan status rencana pengembangan</value> <value>Gagal menyimpan status rencana pengembangan</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>Parametric Transformer telah siap</value> <value>Parametric Transformer telah siap</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>Menjelajahi di Teyvat</value> <value>Menjelajahi di Teyvat</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>Game Launcher</value> <value>Game Launcher</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>Arsip [{0}] berhasil ditambahkan</value> <value>Arsip [{0}] berhasil ditambahkan</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>Selesai</value> <value>Selesai</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>Mengantre</value> <value>Mengantre</value>
</data> </data>
@@ -2034,7 +2010,7 @@
<value>Pratinjau</value> <value>Pratinjau</value>
</data> </data>
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve"> <data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
<value>Statistik</value> <value>全球祈愿统计</value>
</data> </data>
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve"> <data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
<value>Senjata</value> <value>Senjata</value>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>Argumen Awalan</value> <value>Argumen Awalan</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>Umum</value> <value>Umum</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>Backdrop Material</value> <value>Backdrop Material</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>Cache gambar disimpan di sini</value> <value>Cache gambar disimpan di sini</value>
</data> </data>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>キャラクターラインナップ:{0:MM-dd HH:mm}</value> <value>キャラクターラインナップ:{0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>育成計画のステータスを保存できません</value> <value>育成計画のステータスを保存できません</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>参量物質変化器は使用可能</value> <value>参量物質変化器は使用可能</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>テイワット大陸を探索中</value> <value>テイワット大陸を探索中</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>ゲームランチャー</value> <value>ゲームランチャー</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>アーカイブ [{0}] を作成しました</value> <value>アーカイブ [{0}] を作成しました</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>完了</value> <value>完了</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>待機中</value> <value>待機中</value>
</data> </data>
@@ -2034,7 +2010,7 @@
<value>一覧</value> <value>一覧</value>
</data> </data>
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve"> <data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
<value>統計</value> <value>全球祈愿统计</value>
</data> </data>
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve"> <data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
<value>武器</value> <value>武器</value>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>コマンドラインパラメーター</value> <value>コマンドラインパラメーター</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>一般</value> <value>一般</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>テーマ</value> <value>テーマ</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>イメージキャッシュはここに格納されます</value> <value>イメージキャッシュはここに格納されます</value>
</data> </data>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>角色橱窗:{0:MM-dd HH:mm}</value> <value>角色橱窗:{0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>육성 계획 상태를 저장하지 못했습니다</value> <value>육성 계획 상태를 저장하지 못했습니다</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>매개 변수 변환기가 준비되었습니다</value> <value>매개 변수 변환기가 준비되었습니다</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>正在提瓦特大陆中探索</value> <value>正在提瓦特大陆中探索</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>게임 시작</value> <value>게임 시작</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>아카이브 [{0}]가 추가되었습니다</value> <value>아카이브 [{0}]가 추가되었습니다</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>완료</value> <value>완료</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>대기 중</value> <value>대기 중</value>
</data> </data>
@@ -2034,7 +2010,7 @@
<value>개요</value> <value>개요</value>
</data> </data>
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve"> <data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
<value>统计</value> <value>全球祈愿统计</value>
</data> </data>
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve"> <data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
<value>무기</value> <value>무기</value>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>启动参数</value> <value>启动参数</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>보통</value> <value>보통</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>배경 테마</value> <value>배경 테마</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>여기에 저장된 이미지 캐시</value> <value>여기에 저장된 이미지 캐시</value>
</data> </data>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>Exibição de personagens: {0:MM-dd HH:mm}</value> <value>Exibição de personagens: {0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>Falha ao salvar o status do planejamento</value> <value>Falha ao salvar o status do planejamento</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>O Transformador Paramétrico está pronto</value> <value>O Transformador Paramétrico está pronto</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>Explorando em Teyvat</value> <value>Explorando em Teyvat</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>Inicializador</value> <value>Inicializador</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>Arquivo [{0}] adicionado com sucesso</value> <value>Arquivo [{0}] adicionado com sucesso</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>Concluído</value> <value>Concluído</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>Em fila</value> <value>Em fila</value>
</data> </data>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>Argumentos de inicialização</value> <value>Argumentos de inicialização</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>Geral</value> <value>Geral</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>Material de pano de fundo</value> <value>Material de pano de fundo</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>O cache de imagens é salvo aqui</value> <value>O cache de imagens é salvo aqui</value>
</data> </data>
@@ -2571,7 +2532,7 @@
<value>自定义背景图片,支持 bmp / gif / ico / jpg / jpeg / png / tiff / webp 格式</value> <value>自定义背景图片,支持 bmp / gif / ico / jpg / jpeg / png / tiff / webp 格式</value>
</data> </data>
<data name="ViewPageSettingOpenBackgroundImageFolderHeader" xml:space="preserve"> <data name="ViewPageSettingOpenBackgroundImageFolderHeader" xml:space="preserve">
<value>Abrir pasta do fundo</value> <value>打开背景图片文件夹</value>
</data> </data>
<data name="ViewPageSettingResetAction" xml:space="preserve"> <data name="ViewPageSettingResetAction" xml:space="preserve">
<value>Resetar</value> <value>Resetar</value>

View File

@@ -189,15 +189,6 @@
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve"> <data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
<value>[{0}] 热键 [{1}] 注册失败</value> <value>[{0}] 热键 [{1}] 注册失败</value>
</data> </data>
<data name="CoreWindowThemeDark" xml:space="preserve">
<value>深色</value>
</data>
<data name="CoreWindowThemeLight" xml:space="preserve">
<value>浅色</value>
</data>
<data name="CoreWindowThemeSystem" xml:space="preserve">
<value>跟随系统</value>
</data>
<data name="FilePickerExportCommit" xml:space="preserve"> <data name="FilePickerExportCommit" xml:space="preserve">
<value>导出</value> <value>导出</value>
</data> </data>
@@ -869,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>
@@ -2229,7 +2217,7 @@
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value> <value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve"> <data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>自动化任务</value> <value>Better GI</value>
</data> </data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>常规</value> <value>常规</value>
@@ -2247,7 +2235,7 @@
<value>文件</value> <value>文件</value>
</data> </data>
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve"> <data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
<value>进程联动</value> <value>进程</value>
</data> </data>
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve"> <data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
<value>在指定的显示器上运行</value> <value>在指定的显示器上运行</value>
@@ -2636,12 +2624,6 @@
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve"> <data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>评价软件</value> <value>评价软件</value>
</data> </data>
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
<value>更改窗体的颜色主题</value>
</data>
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
<value>颜色主题</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve"> <data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>贡献翻译</value> <value>贡献翻译</value>
</data> </data>
@@ -2651,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>
@@ -2919,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版本更新后).*?~.*?&amp;lt;t class="t_(?:gl|lc)".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value> <value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&amp;lt;t class="t_(?:gl|lc)".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>
</data> </data>
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve"> <data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
<value>〓更新时间〓.+?&amp;lt;t class=\"t_(?:gl|lc)\".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value> <value>〓更新时间〓.+?&amp;lt;t class=\"t_(?:gl|lc)\".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>
@@ -3071,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>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>Демонстрация персонажей: {0:MM-dd HH:mm}</value> <value>Демонстрация персонажей: {0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>Не удалось сохранить статус плана разработки.</value> <value>Не удалось сохранить статус плана разработки.</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>Преобразователь готов</value> <value>Преобразователь готов</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>Исследование Тейвата</value> <value>Исследование Тейвата</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>Game Launcher</value> <value>Game Launcher</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>存档 [{0}] 添加成功</value> <value>存档 [{0}] 添加成功</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>Завершено</value> <value>Завершено</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>В процессе</value> <value>В процессе</value>
</data> </data>
@@ -2034,7 +2010,7 @@
<value>总览</value> <value>总览</value>
</data> </data>
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve"> <data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
<value>统计</value> <value>全球祈愿统计</value>
</data> </data>
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve"> <data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
<value>Оружие</value> <value>Оружие</value>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>启动参数</value> <value>启动参数</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>常规</value> <value>常规</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>背景材质</value> <value>背景材质</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>图片缓存 在此处存放</value> <value>图片缓存 在此处存放</value>
</data> </data>

View File

@@ -767,21 +767,6 @@
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve"> <data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
<value>角色櫥窗:{0:MM-dd HH:mm}</value> <value>角色櫥窗:{0:MM-dd HH:mm}</value>
</data> </data>
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
<value>必应每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
<value>胡桃每日一图</value>
</data>
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
<value>官方启动器壁纸</value>
</data>
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
<value>本地随机图片</value>
</data>
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
<value>无背景图片</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve"> <data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>保存養成計劃狀態失敗</value> <value>保存養成計劃狀態失敗</value>
</data> </data>
@@ -839,9 +824,6 @@
<data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve"> <data name="ServiceDailyNoteNotifierTransformerHint" xml:space="preserve">
<value>參量質變儀已準備完成</value> <value>參量質變儀已準備完成</value>
</data> </data>
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
</data>
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve"> <data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
<value>正在提瓦特大陸中探索</value> <value>正在提瓦特大陸中探索</value>
</data> </data>
@@ -1409,9 +1391,6 @@
<data name="ViewLaunchGameHeader" xml:space="preserve"> <data name="ViewLaunchGameHeader" xml:space="preserve">
<value>啟動遊戲</value> <value>啟動遊戲</value>
</data> </data>
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
<value>管理员模式下无法拖动排序</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve"> <data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>存檔 [{0}] 添加成功</value> <value>存檔 [{0}] 添加成功</value>
</data> </data>
@@ -1691,9 +1670,6 @@
<data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryComplete" xml:space="preserve">
<value>完成</value> <value>完成</value>
</data> </data>
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
<value>响应内容不是有效的文件字节流</value>
</data>
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve"> <data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
<value>待處理</value> <value>待處理</value>
</data> </data>
@@ -2034,7 +2010,7 @@
<value>總覽</value> <value>總覽</value>
</data> </data>
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve"> <data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
<value>統計</value> <value>全球祈愿统计</value>
</data> </data>
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve"> <data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
<value>武器</value> <value>武器</value>
@@ -2210,12 +2186,6 @@
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>啟動參數</value> <value>啟動參數</value>
</data> </data>
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
</data>
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
<value>Better GI</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve"> <data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>一般</value> <value>一般</value>
</data> </data>
@@ -2357,15 +2327,6 @@
<data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve"> <data name="ViewPageSettingBackdropMaterialHeader" xml:space="preserve">
<value>背景材質</value> <value>背景材質</value>
</data> </data>
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
<value>图片版权信息</value>
</data>
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
</data>
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve"> <data name="ViewPageSettingCacheFolderDescription" 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

View File

@@ -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);
} }
} }
} }
@@ -138,7 +133,7 @@ internal sealed partial class AnnouncementService : IAnnouncementService
continue; continue;
} }
MatchCollection matches = AnnouncementRegex.XmlTimeTagRegex().Matches(announcement.Content); MatchCollection matches = AnnouncementRegex.XmlTimeTagRegex.Matches(announcement.Content);
if (matches.Count < 2) if (matches.Count < 2)
{ {
continue; continue;

View File

@@ -1,7 +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 Microsoft.UI.Xaml;
using Snap.Hutao.Core.Windowing; using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Model; using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
@@ -17,7 +16,6 @@ internal sealed partial class AppOptions : DbStoreOptions
{ {
private bool? isEmptyHistoryWishVisible; private bool? isEmptyHistoryWishVisible;
private BackdropType? backdropType; private BackdropType? backdropType;
private ElementTheme? elementTheme;
private BackgroundImageType? backgroundImageType; private BackgroundImageType? backgroundImageType;
private Region? region; private Region? region;
private string? geetestCustomCompositeUrl; private string? geetestCustomCompositeUrl;
@@ -36,19 +34,6 @@ internal sealed partial class AppOptions : DbStoreOptions
set => SetOption(ref backdropType, SettingEntry.SystemBackdropType, value, EnumToStringOrEmpty); set => SetOption(ref backdropType, SettingEntry.SystemBackdropType, value, EnumToStringOrEmpty);
} }
public Lazy<List<NameValue<ElementTheme>>> LazyElementThemes { get; } = new(() =>
[
new(SH.CoreWindowThemeLight, ElementTheme.Light),
new(SH.CoreWindowThemeDark, ElementTheme.Dark),
new(SH.CoreWindowThemeSystem, ElementTheme.Default),
]);
public ElementTheme ElementTheme
{
get => GetOption(ref elementTheme, SettingEntry.ElementTheme, EnumParse<ElementTheme>, ElementTheme.Default).Value;
set => SetOption(ref elementTheme, SettingEntry.ElementTheme, value, EnumToStringOrEmpty);
}
public List<NameValue<BackgroundImageType>> BackgroundImageTypes { get; } = CollectionsNameValue.FromEnum<BackgroundImageType>(type => type.GetLocalizedDescription()); public List<NameValue<BackgroundImageType>> BackgroundImageTypes { get; } = CollectionsNameValue.FromEnum<BackgroundImageType>(type => type.GetLocalizedDescription());
public BackgroundImageType BackgroundImageType public BackgroundImageType BackgroundImageType

View File

@@ -28,16 +28,16 @@ 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];
backgroundSet.Remove(path); backgroundSet.Remove(path);
if (string.Equals(path, previous?.Path, StringComparison.OrdinalIgnoreCase)) if (string.Equals(path, previous?.Path, StringComparison.OrdinalIgnoreCase))
@@ -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 ??= [];

View File

@@ -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);
} }

View File

@@ -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));

View File

@@ -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;
}
} }
} }

View File

@@ -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);
}
}

View File

@@ -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());
} }
} }

View File

@@ -3,10 +3,10 @@
using Snap.Hutao.Core.ExceptionService; 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.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;
@@ -31,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);
} }
@@ -53,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 = [];
@@ -63,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)
@@ -101,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;
} }
@@ -131,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()
{ {
@@ -150,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(),
@@ -167,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),
}; };
} }
} }

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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(),

View File

@@ -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);

View File

@@ -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;
}
} }

View File

@@ -5,6 +5,7 @@ using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.Model.Metadata.Abstraction;
using Snap.Hutao.ViewModel.GachaLog; using Snap.Hutao.ViewModel.GachaLog;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
namespace Snap.Hutao.Service.GachaLog.Factory; namespace Snap.Hutao.Service.GachaLog.Factory;
@@ -14,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 = [];
@@ -46,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;
} }
} }

View File

@@ -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);

View File

@@ -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;
} }
} }

View File

@@ -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);
}
}
}

View File

@@ -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,
]); ]);
} }

View File

@@ -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())
{ {

View File

@@ -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);
} }
} }

View File

@@ -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

View File

@@ -2,9 +2,12 @@
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Weapon;
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;
@@ -37,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)
@@ -52,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())
{ {
@@ -74,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);
} }
@@ -94,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
@@ -125,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)
{ {

View File

@@ -5,10 +5,10 @@ using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.Diagnostics;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.InterChange.GachaLog; using Snap.Hutao.Model.InterChange.GachaLog;
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;
@@ -55,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;
} }
@@ -176,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);

View File

@@ -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)

View File

@@ -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);
} }

View File

@@ -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>
/// 异步上传祈愿记录 /// 异步上传祈愿记录

View File

@@ -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);

View File

@@ -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);

View File

@@ -168,14 +168,9 @@ internal sealed partial class PackageConverter
{ {
try try
{ {
// Server might close the connection shortly, using (Stream remoteSteam = await httpClient.GetStreamAsync(pkgVersionUrl).ConfigureAwait(false))
// we have to cache the content immediately.
using (HttpResponseMessage responseMessage = await httpClient.GetAsync(pkgVersionUrl, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false))
{ {
using (Stream remoteSteam = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false)) return await GetVersionItemsAsync(remoteSteam).ConfigureAwait(false);
{
return await GetVersionItemsAsync(remoteSteam).ConfigureAwait(false);
}
} }
} }
catch (IOException ex) catch (IOException ex)

Some files were not shown because too many files have changed in this diff Show More