mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
1 Commits
feat/1487
...
fix/compos
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e48ce1dd3b |
24
build.cake
24
build.cake
@@ -69,15 +69,6 @@ else if (AppVeyor.IsRunningOnAppVeyor)
|
|||||||
})[..^2];
|
})[..^2];
|
||||||
Information($"Version: {version}");
|
Information($"Version: {version}");
|
||||||
}
|
}
|
||||||
else // Local
|
|
||||||
{
|
|
||||||
repoDir = System.Environment.CurrentDirectory;
|
|
||||||
outputPath = System.IO.Path.Combine(repoDir, "src", "output");
|
|
||||||
|
|
||||||
version = System.DateTime.Now.ToString("yyyy.M.d.") + ((int)((System.DateTime.Now - System.DateTime.Today).TotalSeconds / 86400 * 65535)).ToString();
|
|
||||||
|
|
||||||
Information($"Version: {version}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Task("Build")
|
Task("Build")
|
||||||
.IsDependentOn("Build binary package")
|
.IsDependentOn("Build binary package")
|
||||||
@@ -121,17 +112,6 @@ Task("Generate AppxManifest")
|
|||||||
Information("Using Release configuration");
|
Information("Using Release configuration");
|
||||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"CN=SignPath Foundation, O=SignPath Foundation, L=Lewes, S=Delaware, C=US\"");
|
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"CN=SignPath Foundation, O=SignPath Foundation, L=Lewes, S=Delaware, C=US\"");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Information("Using Local configuration.");
|
|
||||||
content = content
|
|
||||||
.Replace("Snap Hutao", "Snap Hutao Local")
|
|
||||||
.Replace("胡桃", "胡桃 Local")
|
|
||||||
.Replace("DGP Studio", "DGP Studio CI");
|
|
||||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Name=\"([^\"]*)\"", " Name=\"E8B6E2B3-D2A0-4435-A81D-2A16AAF405C7\"");
|
|
||||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"E=admin@dgp-studio.cn, CN=DGP Studio CI, OU=CI, O=DGP-Studio, L=San Jose, S=CA, C=US\"");
|
|
||||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Version=\"([0-9\\.]+)\"", $" Version=\"{version}\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
System.IO.File.WriteAllText(manifest, content);
|
System.IO.File.WriteAllText(manifest, content);
|
||||||
|
|
||||||
@@ -193,10 +173,6 @@ Task("Build MSIX")
|
|||||||
{
|
{
|
||||||
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao-{version}.msix");
|
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao-{version}.msix");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao.Local-{version}.msix");
|
|
||||||
}
|
|
||||||
var p = StartProcess(
|
var p = StartProcess(
|
||||||
"makeappx.exe",
|
"makeappx.exe",
|
||||||
new ProcessSettings
|
new ProcessSettings
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<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.2" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Uri.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/Uri.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///Control/Theme/WindowOverride.xaml"/>
|
<ResourceDictionary Source="ms-appx:///Control/Theme/WindowOverride.xaml"/>
|
||||||
<ResourceDictionary Source="ms-appx:///View/Card/Primitive/CardProgressBar.xaml"/>
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.WinUI;
|
|
||||||
using CommunityToolkit.WinUI.Controls;
|
using CommunityToolkit.WinUI.Controls;
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
|
||||||
using Snap.Hutao.Control.Extension;
|
using Snap.Hutao.Control.Extension;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
namespace Snap.Hutao.Control.AutoSuggestBox;
|
||||||
@@ -23,42 +20,6 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
|||||||
TokenItemAdding += OnTokenItemAdding;
|
TokenItemAdding += OnTokenItemAdding;
|
||||||
TokenItemAdded += OnTokenItemModified;
|
TokenItemAdded += OnTokenItemModified;
|
||||||
TokenItemRemoved += OnTokenItemModified;
|
TokenItemRemoved += OnTokenItemModified;
|
||||||
Loaded += OnLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (this.FindDescendant("SuggestionsPopup") is Popup { Child: Border { Child: ListView listView } border })
|
|
||||||
{
|
|
||||||
IAppResourceProvider appResourceProvider = Ioc.Default.GetRequiredService<IAppResourceProvider>();
|
|
||||||
listView.Background = null;
|
|
||||||
listView.Margin = appResourceProvider.GetResource<Thickness>("AutoSuggestListPadding");
|
|
||||||
|
|
||||||
border.Background = appResourceProvider.GetResource<Microsoft.UI.Xaml.Media.Brush>("AutoSuggestBoxSuggestionsListBackground");
|
|
||||||
border.CornerRadius = new(0, 0, 8, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.FindDescendant("PART_AutoSuggestBox") is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
|
|
||||||
{
|
|
||||||
autoSuggestBox.GotFocus += OnSuggestBoxFocusGot;
|
|
||||||
autoSuggestBox.LosingFocus += OnSuggestBoxFocusLosing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSuggestBoxFocusGot(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
|
|
||||||
{
|
|
||||||
autoSuggestBox.ItemsSource = AvailableTokens.Values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSuggestBoxFocusLosing(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Microsoft.UI.Xaml.Controls.AutoSuggestBox autoSuggestBox)
|
|
||||||
{
|
|
||||||
autoSuggestBox.ItemsSource = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFilterSuggestionRequested(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
private void OnFilterSuggestionRequested(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||||
@@ -71,6 +32,9 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
|||||||
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||||
{
|
{
|
||||||
sender.ItemsSource = AvailableTokens.Values.Where(q => q.Value.Contains(Text, StringComparison.OrdinalIgnoreCase));
|
sender.ItemsSource = AvailableTokens.Values.Where(q => q.Value.Contains(Text, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
// TODO: CornerRadius
|
||||||
|
// Popup? popup = this.FindDescendant("SuggestionsPopup") as Popup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +45,7 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandInvocation.TryExecute(FilterCommand, FilterCommandParameter);
|
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
private void OnTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
||||||
@@ -96,6 +60,6 @@ internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
|||||||
|
|
||||||
private void OnTokenItemModified(TokenizingTextBox sender, object args)
|
private void OnTokenItemModified(TokenizingTextBox sender, object args)
|
||||||
{
|
{
|
||||||
CommandInvocation.TryExecute(FilterCommand, FilterCommandParameter);
|
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Snap.Hutao.Control.Extension;
|
namespace Snap.Hutao.Control.Extension;
|
||||||
|
|
||||||
internal static class CommandInvocation
|
internal static class CommandExtension
|
||||||
{
|
{
|
||||||
public static bool TryExecute(this ICommand? command, object? parameter = null)
|
public static bool TryExecute(this ICommand? command, object? parameter = null)
|
||||||
{
|
{
|
||||||
@@ -2,13 +2,11 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Extension;
|
namespace Snap.Hutao.Control.Extension;
|
||||||
|
|
||||||
internal static class DependencyObjectExtension
|
internal static class DependencyObjectExtension
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static IServiceProvider ServiceProvider(this DependencyObject obj)
|
public static IServiceProvider ServiceProvider(this DependencyObject obj)
|
||||||
{
|
{
|
||||||
return Ioc.Default;
|
return Ioc.Default;
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
using Snap.Hutao.Control.Extension;
|
|
||||||
using Snap.Hutao.Core.Caching;
|
using Snap.Hutao.Core.Caching;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Image;
|
namespace Snap.Hutao.Control.Image;
|
||||||
@@ -28,11 +26,12 @@ internal sealed class CachedImage : Implementation.ImageEx
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override async Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
|
protected override async Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
|
||||||
{
|
{
|
||||||
IImageCache imageCache = this.ServiceProvider().GetRequiredService<IImageCache>();
|
// We can only use Ioc to retrieve IImageCache, no IServiceProvider is available.
|
||||||
|
IImageCache imageCache = Ioc.Default.GetRequiredService<IImageCache>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HutaoException.ThrowIf(string.IsNullOrEmpty(imageUri.Host), HutaoExceptionKind.ImageCacheInvalidUri, SH.ControlImageCachedImageInvalidResourceUri);
|
Verify.Operation(!string.IsNullOrEmpty(imageUri.Host), SH.ControlImageCachedImageInvalidResourceUri);
|
||||||
string file = await imageCache.GetFileFromCacheAsync(imageUri).ConfigureAwait(true); // BitmapImage need to be created by main thread.
|
string file = await imageCache.GetFileFromCacheAsync(imageUri).ConfigureAwait(true); // BitmapImage need to be created by main thread.
|
||||||
token.ThrowIfCancellationRequested(); // check token state to determine whether the operation should be canceled.
|
token.ThrowIfCancellationRequested(); // check token state to determine whether the operation should be canceled.
|
||||||
return new BitmapImage(file.ToUri()); // BitmapImage initialize with a uri will increase image quality and loading speed.
|
return new BitmapImage(file.ToUri()); // BitmapImage initialize with a uri will increase image quality and loading speed.
|
||||||
|
|||||||
@@ -7,14 +7,21 @@ using Windows.Media.Casting;
|
|||||||
|
|
||||||
namespace Snap.Hutao.Control.Image.Implementation;
|
namespace Snap.Hutao.Control.Image.Implementation;
|
||||||
|
|
||||||
[DependencyProperty("NineGrid", typeof(Thickness))]
|
internal class ImageEx : ImageExBase
|
||||||
internal partial class ImageEx : ImageExBase
|
|
||||||
{
|
{
|
||||||
|
private static readonly DependencyProperty NineGridProperty = DependencyProperty.Register(nameof(NineGrid), typeof(Thickness), typeof(ImageEx), new PropertyMetadata(default(Thickness)));
|
||||||
|
|
||||||
public ImageEx()
|
public ImageEx()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Thickness NineGrid
|
||||||
|
{
|
||||||
|
get => (Thickness)GetValue(NineGridProperty);
|
||||||
|
set => SetValue(NineGridProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public override CompositionBrush GetAlphaMask()
|
public override CompositionBrush GetAlphaMask()
|
||||||
{
|
{
|
||||||
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
|
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Microsoft.UI.Composition;
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
using Snap.Hutao.Win32;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
|
|
||||||
@@ -159,6 +158,7 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
control.LayoutUpdated += control.OnImageExBaseLayoutUpdated;
|
control.LayoutUpdated += control.OnImageExBaseLayoutUpdated;
|
||||||
|
|
||||||
control.InvalidateLazyLoading();
|
control.InvalidateLazyLoading();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -169,7 +169,7 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
|
|
||||||
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (d is ImageExBase { EnableLazyLoading: true } control)
|
if (d is ImageExBase control && control.EnableLazyLoading)
|
||||||
{
|
{
|
||||||
control.InvalidateLazyLoading();
|
control.InvalidateLazyLoading();
|
||||||
}
|
}
|
||||||
@@ -229,6 +229,9 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
|
|
||||||
private void AttachPlaceholderSource(ImageSource? source)
|
private void AttachPlaceholderSource(ImageSource? source)
|
||||||
{
|
{
|
||||||
|
// Setting the source at this point should call ImageExOpened/VisualStateManager.GoToState
|
||||||
|
// as we register to both the ImageOpened/ImageFailed events of the underlying control.
|
||||||
|
// We only need to call those methods if we fail in other cases before we get here.
|
||||||
if (PlaceholderImage is Microsoft.UI.Xaml.Controls.Image image)
|
if (PlaceholderImage is Microsoft.UI.Xaml.Controls.Image image)
|
||||||
{
|
{
|
||||||
image.Source = source;
|
image.Source = source;
|
||||||
@@ -237,15 +240,6 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
{
|
{
|
||||||
brush.ImageSource = source;
|
brush.ImageSource = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source is null)
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, UnloadedState, true);
|
|
||||||
}
|
|
||||||
else if (source is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
|
|
||||||
{
|
|
||||||
VisualStateManager.GoToState(this, LoadedState, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SetSource(object? source)
|
private async void SetSource(object? source)
|
||||||
@@ -317,7 +311,8 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
}
|
}
|
||||||
|
|
||||||
tokenSource?.Cancel();
|
tokenSource?.Cancel();
|
||||||
tokenSource = new();
|
|
||||||
|
tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
AttachPlaceholderSource(null);
|
AttachPlaceholderSource(null);
|
||||||
|
|
||||||
@@ -448,10 +443,9 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect controlRect = TransformToVisual(hostElement).TransformBounds(StructMarshal.Rect(ActualSize));
|
Rect controlRect = TransformToVisual(hostElement)
|
||||||
|
.TransformBounds(new Rect(0, 0, ActualWidth, ActualHeight));
|
||||||
double lazyLoadingThreshold = LazyLoadingThreshold;
|
double lazyLoadingThreshold = LazyLoadingThreshold;
|
||||||
|
|
||||||
// Left/Top 1 Threshold, Right/Bottom 2 Threshold
|
|
||||||
Rect hostRect = new(
|
Rect hostRect = new(
|
||||||
0 - lazyLoadingThreshold,
|
0 - lazyLoadingThreshold,
|
||||||
0 - lazyLoadingThreshold,
|
0 - lazyLoadingThreshold,
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Composition;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Hosting;
|
||||||
|
using System.Numerics;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Layout;
|
||||||
|
|
||||||
|
internal sealed class DefaultItemCollectionTransitionProvider : ItemCollectionTransitionProvider
|
||||||
|
{
|
||||||
|
private const double DefaultAnimationDurationInMs = 300.0;
|
||||||
|
|
||||||
|
static DefaultItemCollectionTransitionProvider()
|
||||||
|
{
|
||||||
|
AnimationSlowdownFactor = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double AnimationSlowdownFactor { get; set; }
|
||||||
|
|
||||||
|
protected override bool ShouldAnimateCore(ItemCollectionTransition transition)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void StartTransitions(IList<ItemCollectionTransition> transitions)
|
||||||
|
{
|
||||||
|
List<ItemCollectionTransition> addTransitions = [];
|
||||||
|
List<ItemCollectionTransition> removeTransitions = [];
|
||||||
|
List<ItemCollectionTransition> moveTransitions = [];
|
||||||
|
|
||||||
|
foreach (ItemCollectionTransition transition in addTransitions)
|
||||||
|
{
|
||||||
|
switch (transition.Operation)
|
||||||
|
{
|
||||||
|
case ItemCollectionTransitionOperation.Add:
|
||||||
|
addTransitions.Add(transition);
|
||||||
|
break;
|
||||||
|
case ItemCollectionTransitionOperation.Remove:
|
||||||
|
removeTransitions.Add(transition);
|
||||||
|
break;
|
||||||
|
case ItemCollectionTransitionOperation.Move:
|
||||||
|
moveTransitions.Add(transition);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StartAddTransitions(addTransitions, removeTransitions.Count > 0, moveTransitions.Count > 0);
|
||||||
|
StartRemoveTransitions(removeTransitions);
|
||||||
|
StartMoveTransitions(moveTransitions, removeTransitions.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartAddTransitions(IList<ItemCollectionTransition> transitions, bool hasRemoveTransitions, bool hasMoveTransitions)
|
||||||
|
{
|
||||||
|
foreach (ItemCollectionTransition transition in transitions)
|
||||||
|
{
|
||||||
|
ItemCollectionTransitionProgress progress = transition.Start();
|
||||||
|
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
|
||||||
|
Compositor compositor = visual.Compositor;
|
||||||
|
|
||||||
|
ScalarKeyFrameAnimation fadeInAnimation = compositor.CreateScalarKeyFrameAnimation();
|
||||||
|
fadeInAnimation.InsertKeyFrame(0.0f, 0.0f);
|
||||||
|
|
||||||
|
if (hasMoveTransitions && hasRemoveTransitions)
|
||||||
|
{
|
||||||
|
fadeInAnimation.InsertKeyFrame(0.66f, 0.0f);
|
||||||
|
}
|
||||||
|
else if (hasMoveTransitions || hasRemoveTransitions)
|
||||||
|
{
|
||||||
|
fadeInAnimation.InsertKeyFrame(0.5f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fadeInAnimation.InsertKeyFrame(1.0f, 1.0f);
|
||||||
|
fadeInAnimation.Duration = TimeSpan.FromMilliseconds(
|
||||||
|
DefaultAnimationDurationInMs * ((hasRemoveTransitions ? 1 : 0) + (hasMoveTransitions ? 1 : 0) + 1) * AnimationSlowdownFactor);
|
||||||
|
|
||||||
|
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
|
||||||
|
visual.StartAnimation("Opacity", fadeInAnimation);
|
||||||
|
batch.End();
|
||||||
|
batch.Completed += (_, _) => progress.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartRemoveTransitions(IList<ItemCollectionTransition> transitions)
|
||||||
|
{
|
||||||
|
foreach (ItemCollectionTransition transition in transitions)
|
||||||
|
{
|
||||||
|
ItemCollectionTransitionProgress progress = transition.Start();
|
||||||
|
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
|
||||||
|
Compositor compositor = visual.Compositor;
|
||||||
|
|
||||||
|
ScalarKeyFrameAnimation fadeOutAnimation = compositor.CreateScalarKeyFrameAnimation();
|
||||||
|
fadeOutAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue");
|
||||||
|
fadeOutAnimation.InsertKeyFrame(1.0f, 0.0f);
|
||||||
|
fadeOutAnimation.Duration = TimeSpan.FromMilliseconds(DefaultAnimationDurationInMs * AnimationSlowdownFactor);
|
||||||
|
|
||||||
|
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
|
||||||
|
visual.StartAnimation(nameof(Visual.Opacity), fadeOutAnimation);
|
||||||
|
batch.End();
|
||||||
|
batch.Completed += (_, _) =>
|
||||||
|
{
|
||||||
|
visual.Opacity = 1.0f;
|
||||||
|
progress.Complete();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartMoveTransitions(IList<ItemCollectionTransition> transitions, bool hasRemoveAnimations)
|
||||||
|
{
|
||||||
|
foreach (ItemCollectionTransition transition in transitions)
|
||||||
|
{
|
||||||
|
ItemCollectionTransitionProgress progress = transition.Start();
|
||||||
|
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
|
||||||
|
Compositor compositor = visual.Compositor;
|
||||||
|
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
|
||||||
|
|
||||||
|
// Animate offset.
|
||||||
|
if (transition.OldBounds.X != transition.NewBounds.X ||
|
||||||
|
transition.OldBounds.Y != transition.NewBounds.Y)
|
||||||
|
{
|
||||||
|
AnimateOffset(visual, compositor, transition.OldBounds, transition.NewBounds, hasRemoveAnimations);
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.End();
|
||||||
|
batch.Completed += (_, _) => progress.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnimateOffset(Visual visual, Compositor compositor, Rect oldBounds, Rect newBounds, bool hasRemoveAnimations)
|
||||||
|
{
|
||||||
|
Vector2KeyFrameAnimation offsetAnimation = compositor.CreateVector2KeyFrameAnimation();
|
||||||
|
|
||||||
|
offsetAnimation.SetVector2Parameter("delta", new Vector2(
|
||||||
|
(float)(oldBounds.X - newBounds.X),
|
||||||
|
(float)(oldBounds.Y - newBounds.Y)));
|
||||||
|
offsetAnimation.SetVector2Parameter("final", default);
|
||||||
|
offsetAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue + delta");
|
||||||
|
if (hasRemoveAnimations)
|
||||||
|
{
|
||||||
|
offsetAnimation.InsertExpressionKeyFrame(0.5f, "delta");
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetAnimation.InsertExpressionKeyFrame(1.0f, "final");
|
||||||
|
offsetAnimation.Duration = TimeSpan.FromMilliseconds(
|
||||||
|
DefaultAnimationDurationInMs * ((hasRemoveAnimations ? 1 : 0) + 1) * AnimationSlowdownFactor);
|
||||||
|
|
||||||
|
visual.StartAnimation("TransformMatrix._41_42", offsetAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
|
|
||||||
@@ -19,12 +18,14 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
|
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
|
||||||
{
|
{
|
||||||
context.LayoutState = new UniformStaggeredLayoutState(context);
|
context.LayoutState = new UniformStaggeredLayoutState(context);
|
||||||
|
base.InitializeForContextCore(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
|
protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
|
||||||
{
|
{
|
||||||
context.LayoutState = null;
|
context.LayoutState = null;
|
||||||
|
base.UninitializeForContextCore(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -81,10 +82,16 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
|
|
||||||
(int numberOfColumns, double columnWidth) = GetNumberOfColumnsAndWidth(availableWidth, MinItemWidth, MinColumnSpacing);
|
(int numberOfColumns, double columnWidth) = GetNumberOfColumnsAndWidth(availableWidth, MinItemWidth, MinColumnSpacing);
|
||||||
|
|
||||||
|
if (columnWidth != state.ColumnWidth)
|
||||||
|
{
|
||||||
|
// The items will need to be remeasured
|
||||||
|
state.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
state.ColumnWidth = columnWidth;
|
state.ColumnWidth = columnWidth;
|
||||||
|
|
||||||
double totalWidth = ((state.ColumnWidth + MinColumnSpacing) * numberOfColumns) - MinColumnSpacing;
|
// adjust for column spacing on all columns expect the first
|
||||||
|
double totalWidth = state.ColumnWidth + ((numberOfColumns - 1) * (state.ColumnWidth + MinColumnSpacing));
|
||||||
if (totalWidth > availableWidth)
|
if (totalWidth > availableWidth)
|
||||||
{
|
{
|
||||||
numberOfColumns--;
|
numberOfColumns--;
|
||||||
@@ -96,6 +103,7 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
|
|
||||||
if (numberOfColumns != state.NumberOfColumns)
|
if (numberOfColumns != state.NumberOfColumns)
|
||||||
{
|
{
|
||||||
|
// The items will not need to be remeasured, but they will need to go into new columns
|
||||||
state.ClearColumns();
|
state.ClearColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +170,7 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
item.Element.Measure(new Size(state.ColumnWidth, availableHeight));
|
item.Element.Measure(new Size(state.ColumnWidth, availableHeight));
|
||||||
if (item.Height != item.Element.DesiredSize.Height)
|
if (item.Height != item.Element.DesiredSize.Height)
|
||||||
{
|
{
|
||||||
// this item changed size; we need to recalculate layout for everything after this item
|
// this item changed size; we need to recalculate layout for everything after this
|
||||||
state.RemoveFromIndex(i + 1);
|
state.RemoveFromIndex(i + 1);
|
||||||
item.Height = item.Element.DesiredSize.Height;
|
item.Height = item.Element.DesiredSize.Height;
|
||||||
columnHeights[columnIndex] = item.Top + item.Height;
|
columnHeights[columnIndex] = item.Top + item.Height;
|
||||||
@@ -193,16 +201,16 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
// Cycle through each column and arrange the items that are within the realization bounds
|
// Cycle through each column and arrange the items that are within the realization bounds
|
||||||
for (int columnIndex = 0; columnIndex < state.NumberOfColumns; columnIndex++)
|
for (int columnIndex = 0; columnIndex < state.NumberOfColumns; columnIndex++)
|
||||||
{
|
{
|
||||||
foreach (ref readonly UniformStaggeredItem item in CollectionsMarshal.AsSpan(state.GetColumnLayout(columnIndex)))
|
UniformStaggeredColumnLayout layout = state.GetColumnLayout(columnIndex);
|
||||||
|
foreach (ref readonly UniformStaggeredItem item in CollectionsMarshal.AsSpan(layout))
|
||||||
{
|
{
|
||||||
double bottom = item.Top + item.Height;
|
double bottom = item.Top + item.Height;
|
||||||
if (bottom < context.RealizationRect.Top)
|
if (bottom < context.RealizationRect.Top)
|
||||||
{
|
{
|
||||||
// Element is above the realization bounds
|
// element is above the realization bounds
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial or fully in the view
|
|
||||||
if (item.Top <= context.RealizationRect.Bottom)
|
if (item.Top <= context.RealizationRect.Bottom)
|
||||||
{
|
{
|
||||||
double itemHorizontalOffset = (state.ColumnWidth * columnIndex) + (MinColumnSpacing * columnIndex);
|
double itemHorizontalOffset = (state.ColumnWidth * columnIndex) + (MinColumnSpacing * columnIndex);
|
||||||
@@ -221,22 +229,21 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
return finalSize;
|
return finalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (int NumberOfColumns, double ColumnWidth) GetNumberOfColumnsAndWidth(double availableWidth, double minItemWidth, double columnSpacing)
|
private static (int NumberOfColumns, double ColumnWidth) GetNumberOfColumnsAndWidth(double availableWidth, double minItemWidth, double minColumnSpacing)
|
||||||
{
|
{
|
||||||
// test if the width can fit in 2 items
|
// test if the width can fit in 2 items
|
||||||
if ((2 * minItemWidth) + columnSpacing > availableWidth)
|
if ((2 * minItemWidth) + minColumnSpacing > availableWidth)
|
||||||
{
|
{
|
||||||
return (1, availableWidth);
|
return (1, availableWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
int columnCount = Math.Max(1, (int)((availableWidth + columnSpacing) / (minItemWidth + columnSpacing)));
|
int columnCount = Math.Max(1, (int)((availableWidth + minColumnSpacing) / (minItemWidth + minColumnSpacing)));
|
||||||
double columnWidthWithSpacing = (availableWidth + columnSpacing) / columnCount;
|
double columnWidthAddSpacing = (availableWidth + minColumnSpacing) / columnCount;
|
||||||
return (columnCount, columnWidthWithSpacing - columnSpacing);
|
return (columnCount, columnWidthAddSpacing - minColumnSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetLowestColumnIndex(in ReadOnlySpan<double> columnHeights)
|
private static int GetLowestColumnIndex(in ReadOnlySpan<double> columnHeights)
|
||||||
{
|
{
|
||||||
// We want to find the leftest column with the lowest height
|
|
||||||
int columnIndex = 0;
|
int columnIndex = 0;
|
||||||
double height = columnHeights[0];
|
double height = columnHeights[0];
|
||||||
for (int j = 1; j < columnHeights.Length; j++)
|
for (int j = 1; j < columnHeights.Length; j++)
|
||||||
@@ -253,11 +260,13 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
|||||||
|
|
||||||
private static void OnMinItemWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
private static void OnMinItemWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
((UniformStaggeredLayout)d).InvalidateMeasure();
|
UniformStaggeredLayout panel = (UniformStaggeredLayout)d;
|
||||||
|
panel.InvalidateMeasure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
((UniformStaggeredLayout)d).InvalidateMeasure();
|
UniformStaggeredLayout panel = (UniformStaggeredLayout)d;
|
||||||
|
panel.InvalidateMeasure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -66,6 +67,46 @@ internal sealed class UniformStaggeredLayoutState
|
|||||||
return columnLayout[columnIndex];
|
return columnLayout[columnIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear everything that has been calculated.
|
||||||
|
/// </summary>
|
||||||
|
internal void Clear()
|
||||||
|
{
|
||||||
|
// https://github.com/DGP-Studio/Snap.Hutao/issues/1079
|
||||||
|
// The first element must be force refreshed otherwise
|
||||||
|
// it will use the old one realized
|
||||||
|
// https://github.com/DGP-Studio/Snap.Hutao/issues/1099
|
||||||
|
// Now we need to refresh the first element of each column
|
||||||
|
// https://github.com/DGP-Studio/Snap.Hutao/issues/1099
|
||||||
|
// Finally we need to refresh the whole layout when we reset
|
||||||
|
if (context.ItemCount > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < context.ItemCount; i++)
|
||||||
|
{
|
||||||
|
RecycleElementAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
columnLayout.Clear();
|
||||||
|
items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear the layout columns so they will be recalculated.
|
||||||
|
/// </summary>
|
||||||
|
internal void ClearColumns()
|
||||||
|
{
|
||||||
|
columnLayout.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the estimated height of the layout.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The estimated height of the layout.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// If all of the items have been calculated then the actual height will be returned.
|
||||||
|
/// If all of the items have not been calculated then an estimated height will be calculated based on the average height of the items.
|
||||||
|
/// </remarks>
|
||||||
internal double GetHeight()
|
internal double GetHeight()
|
||||||
{
|
{
|
||||||
double desiredHeight = columnLayout.Values.Max(c => c.Height);
|
double desiredHeight = columnLayout.Values.Max(c => c.Height);
|
||||||
@@ -98,37 +139,10 @@ internal sealed class UniformStaggeredLayoutState
|
|||||||
return desiredHeight;
|
return desiredHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Clear()
|
|
||||||
{
|
|
||||||
RecycleElements();
|
|
||||||
ClearColumns();
|
|
||||||
ClearItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ClearColumns()
|
|
||||||
{
|
|
||||||
columnLayout.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ClearItems()
|
|
||||||
{
|
|
||||||
items.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RecycleElements()
|
|
||||||
{
|
|
||||||
if (context.ItemCount > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < items.Count; i++)
|
|
||||||
{
|
|
||||||
RecycleElementAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RecycleElementAt(int index)
|
internal void RecycleElementAt(int index)
|
||||||
{
|
{
|
||||||
context.RecycleElement(context.GetOrCreateElementAt(index));
|
UIElement element = context.GetOrCreateElementAt(index);
|
||||||
|
context.RecycleElement(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RemoveFromIndex(int index)
|
internal void RemoveFromIndex(int index)
|
||||||
@@ -161,7 +175,7 @@ internal sealed class UniformStaggeredLayoutState
|
|||||||
{
|
{
|
||||||
for (int i = startIndex; i <= endIndex; i++)
|
for (int i = startIndex; i <= endIndex; i++)
|
||||||
{
|
{
|
||||||
if (i >= items.Count)
|
if (i > items.Count)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -170,7 +184,7 @@ internal sealed class UniformStaggeredLayoutState
|
|||||||
item.Height = 0;
|
item.Height = 0;
|
||||||
item.Top = 0;
|
item.Top = 0;
|
||||||
|
|
||||||
// We must recycle all removed elements to ensure that it gets the correct context
|
// We must recycle all elements to ensure that it gets the correct context
|
||||||
RecycleElementAt(i);
|
RecycleElementAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ internal sealed class UInt32Extension : MarkupExtension
|
|||||||
|
|
||||||
protected override object ProvideValue()
|
protected override object ProvideValue()
|
||||||
{
|
{
|
||||||
return XamlBindingHelper.ConvertValue(typeof(uint), Value);
|
_ = uint.TryParse(Value, out uint result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,24 @@ internal static class SoftwareBitmapExtension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe double Luminance(this SoftwareBitmap softwareBitmap)
|
||||||
|
{
|
||||||
|
using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read))
|
||||||
|
{
|
||||||
|
using (IMemoryBufferReference reference = buffer.CreateReference())
|
||||||
|
{
|
||||||
|
reference.As<IMemoryBufferByteAccess>().GetBuffer(out Span<Bgra32> bytes);
|
||||||
|
double sum = 0;
|
||||||
|
foreach (ref readonly Bgra32 pixel in bytes)
|
||||||
|
{
|
||||||
|
sum += pixel.Luminance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / bytes.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static unsafe Bgra32 GetAccentColor(this SoftwareBitmap softwareBitmap)
|
public static unsafe Bgra32 GetAccentColor(this SoftwareBitmap softwareBitmap)
|
||||||
{
|
{
|
||||||
using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read))
|
using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read))
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel
|
|||||||
(d as EqualPanel)?.InvalidateMeasure();
|
(d as EqualPanel)?.InvalidateMeasure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnHorizontalAlignmentChanged(DependencyObject d, DependencyProperty dp)
|
private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
|
||||||
{
|
{
|
||||||
(d as EqualPanel)?.InvalidateMeasure();
|
InvalidateMeasure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Windows.Foundation;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Panel;
|
|
||||||
|
|
||||||
[DependencyProperty("MinItemWidth", typeof(double))]
|
|
||||||
[DependencyProperty("Spacing", typeof(double))]
|
|
||||||
internal partial class HorizontalEqualPanel : Microsoft.UI.Xaml.Controls.Panel
|
|
||||||
{
|
|
||||||
public HorizontalEqualPanel()
|
|
||||||
{
|
|
||||||
Loaded += OnLoaded;
|
|
||||||
SizeChanged += OnSizeChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
|
||||||
{
|
|
||||||
foreach (UIElement child in Children)
|
|
||||||
{
|
|
||||||
// ScrollViewer will always return an Infinity Size, we should use ActualWidth for this situation.
|
|
||||||
double availableWidth = double.IsInfinity(availableSize.Width) ? ActualWidth : availableSize.Width;
|
|
||||||
double childAvailableWidth = (availableWidth + Spacing) / Children.Count;
|
|
||||||
double childMaxAvailableWidth = Math.Max(MinItemWidth, childAvailableWidth);
|
|
||||||
child.Measure(new(childMaxAvailableWidth - Spacing, ActualHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.MeasureOverride(availableSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
|
||||||
{
|
|
||||||
int itemCount = Children.Count;
|
|
||||||
double availableItemWidth = (finalSize.Width - (Spacing * (itemCount - 1))) / itemCount;
|
|
||||||
double actualItemWidth = Math.Max(MinItemWidth, availableItemWidth);
|
|
||||||
|
|
||||||
double offset = 0;
|
|
||||||
foreach (UIElement child in Children)
|
|
||||||
{
|
|
||||||
child.Arrange(new Rect(offset, 0, actualItemWidth, finalSize.Height));
|
|
||||||
offset += actualItemWidth + Spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnLoaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
HorizontalEqualPanel panel = (HorizontalEqualPanel)sender;
|
|
||||||
panel.MinWidth = (panel.MinItemWidth * panel.Children.Count) + (panel.Spacing * (panel.Children.Count - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
((HorizontalEqualPanel)sender).InvalidateMeasure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -72,11 +72,7 @@ internal class ScopedPage : Page
|
|||||||
DisposeViewModel();
|
DisposeViewModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.IsDisposed())
|
DataContext = null;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unloaded -= unloadEventHandler;
|
Unloaded -= unloadEventHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,21 @@
|
|||||||
xmlns:cwm="using:CommunityToolkit.WinUI.Media">
|
xmlns:cwm="using:CommunityToolkit.WinUI.Media">
|
||||||
<ResourceDictionary.ThemeDictionaries>
|
<ResourceDictionary.ThemeDictionaries>
|
||||||
<ResourceDictionary x:Key="Light">
|
<ResourceDictionary x:Key="Light">
|
||||||
<x:Double x:Key="CompatShadowThemeOpacity">0.14</x:Double>
|
<cwm:AttachedCardShadow
|
||||||
|
x:Key="CompatCardShadow"
|
||||||
|
BlurRadius="8"
|
||||||
|
Opacity="0.14"
|
||||||
|
Offset="0,4,0"/>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
<ResourceDictionary x:Key="Dark">
|
<ResourceDictionary x:Key="Dark">
|
||||||
<x:Double x:Key="CompatShadowThemeOpacity">0.28</x:Double>
|
<cwm:AttachedCardShadow
|
||||||
|
x:Key="CompatCardShadow"
|
||||||
|
BlurRadius="8"
|
||||||
|
Opacity="0.28"
|
||||||
|
Offset="0,4,0"/>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</ResourceDictionary.ThemeDictionaries>
|
</ResourceDictionary.ThemeDictionaries>
|
||||||
|
|
||||||
<cwm:AttachedCardShadow
|
|
||||||
x:Key="CompatCardShadow"
|
|
||||||
BlurRadius="8"
|
|
||||||
Opacity="{ThemeResource CompatShadowThemeOpacity}"
|
|
||||||
Offset="0,4,0"/>
|
|
||||||
|
|
||||||
<Style x:Key="BorderCardStyle" TargetType="Border">
|
<Style x:Key="BorderCardStyle" TargetType="Border">
|
||||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
|
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
|
||||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
|
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing0Template">
|
<ItemsPanelTemplate x:Key="WrapPanelSpacing0Template">
|
||||||
<cwcont:WrapPanel/>
|
<cwcont:WrapPanel/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing2Template">
|
|
||||||
<cwcont:WrapPanel HorizontalSpacing="2" VerticalSpacing="2"/>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing4Template">
|
<ItemsPanelTemplate x:Key="WrapPanelSpacing4Template">
|
||||||
<cwcont:WrapPanel HorizontalSpacing="4" VerticalSpacing="4"/>
|
<cwcont:WrapPanel HorizontalSpacing="4" VerticalSpacing="4"/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Win32;
|
|
||||||
using Windows.UI;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Theme;
|
|
||||||
|
|
||||||
internal static class SystemColors
|
|
||||||
{
|
|
||||||
public static Color BaseLowColor(bool isDarkMode)
|
|
||||||
{
|
|
||||||
return isDarkMode ? StructMarshal.Color(0x33FFFFFF) : StructMarshal.Color(0x33000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color BaseMediumLowColor(bool isDarkMode)
|
|
||||||
{
|
|
||||||
return isDarkMode ? StructMarshal.Color(0x66FFFFFF) : StructMarshal.Color(0x66000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color BaseHighColor(bool isDarkMode)
|
|
||||||
{
|
|
||||||
return isDarkMode ? StructMarshal.Color(0xFFFFFFFF) : StructMarshal.Color(0xFF000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,14 +32,6 @@ internal sealed class HutaoException : Exception
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ThrowIfNot(bool condition, HutaoExceptionKind kind, string message, Exception? innerException = default)
|
|
||||||
{
|
|
||||||
if (!condition)
|
|
||||||
{
|
|
||||||
throw new HutaoException(kind, message, innerException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HutaoException ServiceTypeCastFailed<TFrom, TTo>(string name, Exception? innerException = default)
|
public static HutaoException ServiceTypeCastFailed<TFrom, TTo>(string name, Exception? innerException = default)
|
||||||
{
|
{
|
||||||
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}'";
|
||||||
|
|||||||
@@ -6,16 +6,8 @@ namespace Snap.Hutao.Core.ExceptionService;
|
|||||||
internal enum HutaoExceptionKind
|
internal enum HutaoExceptionKind
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
|
||||||
// Foundation
|
|
||||||
ServiceTypeCastFailed,
|
ServiceTypeCastFailed,
|
||||||
ImageCacheInvalidUri,
|
|
||||||
|
|
||||||
// IO
|
|
||||||
FileSystemCreateFileInsufficientPermissions,
|
FileSystemCreateFileInsufficientPermissions,
|
||||||
PrivateNamedPipeContentHashIncorrect,
|
PrivateNamedPipeContentHashIncorrect,
|
||||||
|
|
||||||
// Service
|
|
||||||
GachaStatisticsInvalidItemId,
|
GachaStatisticsInvalidItemId,
|
||||||
GameFpsUnlockingFailed,
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,6 @@ namespace Snap.Hutao.Core.Validation;
|
|||||||
/// 封装验证方法,简化微软验证
|
/// 封装验证方法,简化微软验证
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Obsolete("Use HutaoException instead")]
|
|
||||||
internal static class Must
|
internal static class Must
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using Snap.Hutao.Win32;
|
|||||||
using Snap.Hutao.Win32.Foundation;
|
using Snap.Hutao.Win32.Foundation;
|
||||||
using Snap.Hutao.Win32.Graphics.Dwm;
|
using Snap.Hutao.Win32.Graphics.Dwm;
|
||||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||||
using System.Collections.Frozen;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
@@ -57,22 +56,25 @@ internal sealed class WindowController
|
|||||||
private void InitializeCore()
|
private void InitializeCore()
|
||||||
{
|
{
|
||||||
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
|
||||||
|
|
||||||
window.AppWindow.Title = SH.FormatAppNameAndVersion(runtimeOptions.Version);
|
window.AppWindow.Title = SH.FormatAppNameAndVersion(runtimeOptions.Version);
|
||||||
window.AppWindow.SetIcon(Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"));
|
window.AppWindow.SetIcon(Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"));
|
||||||
ExtendsContentIntoTitleBar();
|
ExtendsContentIntoTitleBar();
|
||||||
|
|
||||||
RecoverOrInitWindowSize();
|
RecoverOrInitWindowSize();
|
||||||
UpdateElementTheme(appOptions.ElementTheme);
|
|
||||||
UpdateImmersiveDarkMode(options.TitleBar, default!);
|
UpdateImmersiveDarkMode(options.TitleBar, default!);
|
||||||
|
|
||||||
// appWindow.Show(true);
|
// appWindow.Show(true);
|
||||||
// appWindow.Show can't bring window to top.
|
// appWindow.Show can't bring window to top.
|
||||||
window.Activate();
|
window.Activate();
|
||||||
options.BringToForeground();
|
options.BringToForeground();
|
||||||
UpdateSystemBackdrop(appOptions.BackdropType);
|
|
||||||
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
if (options.UseSystemBackdrop)
|
||||||
|
{
|
||||||
|
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||||
|
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||||
|
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
subclass.Initialize();
|
subclass.Initialize();
|
||||||
|
|
||||||
@@ -188,12 +190,12 @@ internal sealed class WindowController
|
|||||||
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||||
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||||
|
|
||||||
bool isDarkMode = Control.Theme.ThemeHelper.IsDarkMode(options.TitleBar.ActualTheme);
|
IAppResourceProvider resourceProvider = serviceProvider.GetRequiredService<IAppResourceProvider>();
|
||||||
|
|
||||||
Color systemBaseLowColor = Control.Theme.SystemColors.BaseLowColor(isDarkMode);
|
Color systemBaseLowColor = resourceProvider.GetResource<Color>("SystemBaseLowColor");
|
||||||
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
|
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
|
||||||
|
|
||||||
Color systemBaseMediumLowColor = Control.Theme.SystemColors.BaseMediumLowColor(isDarkMode);
|
Color systemBaseMediumLowColor = resourceProvider.GetResource<Color>("SystemBaseMediumLowColor");
|
||||||
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
|
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
|
||||||
|
|
||||||
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
|
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
|
||||||
@@ -201,7 +203,7 @@ internal sealed class WindowController
|
|||||||
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
|
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
|
||||||
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
|
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
|
||||||
|
|
||||||
Color systemBaseHighColor = Control.Theme.SystemColors.BaseHighColor(isDarkMode);
|
Color systemBaseHighColor = resourceProvider.GetResource<Color>("SystemBaseHighColor");
|
||||||
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
|
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
|
||||||
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
|
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
|
||||||
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
||||||
|
|||||||
@@ -41,18 +41,21 @@ internal readonly struct WindowOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool PersistSize;
|
public readonly bool PersistSize;
|
||||||
|
|
||||||
|
public readonly bool UseSystemBackdrop;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否使用 Win UI 3 自带的拓展标题栏实现
|
/// 是否使用 Win UI 3 自带的拓展标题栏实现
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
||||||
|
|
||||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false)
|
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false, bool useSystemBackdrop = true)
|
||||||
{
|
{
|
||||||
Hwnd = WindowNative.GetWindowHandle(window);
|
Hwnd = WindowNative.GetWindowHandle(window);
|
||||||
InputNonClientPointerSource = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
|
InputNonClientPointerSource = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
|
||||||
TitleBar = titleBar;
|
TitleBar = titleBar;
|
||||||
InitSize = initSize;
|
InitSize = initSize;
|
||||||
PersistSize = persistSize;
|
PersistSize = persistSize;
|
||||||
|
UseSystemBackdrop = useSystemBackdrop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Core.LifeCycle;
|
using Snap.Hutao.Core.LifeCycle;
|
||||||
using Snap.Hutao.Service;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Factory.ContentDialog;
|
namespace Snap.Hutao.Factory.ContentDialog;
|
||||||
|
|
||||||
@@ -16,7 +15,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
private readonly ICurrentWindowReference currentWindowReference;
|
private readonly ICurrentWindowReference currentWindowReference;
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly AppOptions appOptions;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ContentDialogResult> CreateForConfirmAsync(string title, string content)
|
public async ValueTask<ContentDialogResult> CreateForConfirmAsync(string title, string content)
|
||||||
@@ -29,7 +27,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
Content = content,
|
Content = content,
|
||||||
DefaultButton = ContentDialogButton.Primary,
|
DefaultButton = ContentDialogButton.Primary,
|
||||||
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
||||||
RequestedTheme = appOptions.ElementTheme,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return await dialog.ShowAsync();
|
return await dialog.ShowAsync();
|
||||||
@@ -47,7 +44,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
DefaultButton = defaultButton,
|
DefaultButton = defaultButton,
|
||||||
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
PrimaryButtonText = SH.ContentDialogConfirmPrimaryButtonText,
|
||||||
CloseButtonText = SH.ContentDialogCancelCloseButtonText,
|
CloseButtonText = SH.ContentDialogCancelCloseButtonText,
|
||||||
RequestedTheme = appOptions.ElementTheme,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return await dialog.ShowAsync();
|
return await dialog.ShowAsync();
|
||||||
@@ -62,7 +58,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
XamlRoot = currentWindowReference.GetXamlRoot(),
|
XamlRoot = currentWindowReference.GetXamlRoot(),
|
||||||
Title = title,
|
Title = title,
|
||||||
Content = new ProgressBar() { IsIndeterminate = true },
|
Content = new ProgressBar() { IsIndeterminate = true },
|
||||||
RequestedTheme = appOptions.ElementTheme,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
@@ -74,7 +69,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
TContentDialog contentDialog = serviceProvider.CreateInstance<TContentDialog>(parameters);
|
TContentDialog contentDialog = serviceProvider.CreateInstance<TContentDialog>(parameters);
|
||||||
contentDialog.XamlRoot = currentWindowReference.GetXamlRoot();
|
contentDialog.XamlRoot = currentWindowReference.GetXamlRoot();
|
||||||
contentDialog.RequestedTheme = appOptions.ElementTheme;
|
|
||||||
return contentDialog;
|
return contentDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +77,6 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
{
|
{
|
||||||
TContentDialog contentDialog = serviceProvider.CreateInstance<TContentDialog>(parameters);
|
TContentDialog contentDialog = serviceProvider.CreateInstance<TContentDialog>(parameters);
|
||||||
contentDialog.XamlRoot = currentWindowReference.GetXamlRoot();
|
contentDialog.XamlRoot = currentWindowReference.GetXamlRoot();
|
||||||
contentDialog.RequestedTheme = appOptions.ElementTheme;
|
|
||||||
return contentDialog;
|
return contentDialog;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前版本
|
/// 当前版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CurrentVersion = "v3.0";
|
public const string CurrentVersion = "v2.4";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信息
|
/// 信息
|
||||||
@@ -61,7 +61,6 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
|||||||
"v2.2" => UIGFVersion.Major2Minor2OrLower,
|
"v2.2" => UIGFVersion.Major2Minor2OrLower,
|
||||||
"v2.3" => UIGFVersion.Major2Minor3OrHigher,
|
"v2.3" => UIGFVersion.Major2Minor3OrHigher,
|
||||||
"v2.4" => UIGFVersion.Major2Minor3OrHigher,
|
"v2.4" => UIGFVersion.Major2Minor3OrHigher,
|
||||||
"v3.0" => UIGFVersion.Major2Minor3OrHigher,
|
|
||||||
_ => UIGFVersion.NotSupported,
|
_ => UIGFVersion.NotSupported,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ internal static class MonsterRelationship
|
|||||||
5112U => 511U, // 历经百战的浊水喷吐幻灵
|
5112U => 511U, // 历经百战的浊水喷吐幻灵
|
||||||
30605U => 30603U, // 历经百战的霜剑律从
|
30605U => 30603U, // 历经百战的霜剑律从
|
||||||
30606U => 30604U, // 历经百战的幽风铃兰
|
30606U => 30604U, // 历经百战的幽风铃兰
|
||||||
40632U => 40613U, // 自律超算型场力发生装置
|
|
||||||
60402U => 60401U, // (火)岩龙蜥
|
60402U => 60401U, // (火)岩龙蜥
|
||||||
60403U => 60401U, // (冰)岩龙蜥
|
60403U => 60401U, // (冰)岩龙蜥
|
||||||
60404U => 60401U, // (雷)岩龙蜥
|
60404U => 60401U, // (雷)岩龙蜥
|
||||||
|
|||||||
@@ -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.8.0" />
|
Version="1.9.7.0" />
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Snap Hutao</DisplayName>
|
<DisplayName>Snap Hutao</DisplayName>
|
||||||
|
|||||||
@@ -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.8.0" />
|
Version="1.9.7.0" />
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Snap Hutao Dev</DisplayName>
|
<DisplayName>Snap Hutao Dev</DisplayName>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -186,9 +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="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>Register [{0}] hotkey [{1}] failed</value>
|
|
||||||
</data>
|
|
||||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||||
<value>Dark</value>
|
<value>Dark</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -869,9 +866,6 @@
|
|||||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||||
<value>Character Event Wish</value>
|
<value>Character Event Wish</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
|
||||||
<value>Chronicled Wish</value>
|
|
||||||
</data>
|
|
||||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||||
<value>Wanderlust Invocation</value>
|
<value>Wanderlust Invocation</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2229,7 +2223,7 @@
|
|||||||
<value>Auto start Better GUI for automation tasks after game launched</value>
|
<value>Auto start Better GUI for automation tasks after game launched</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||||
<value>Automated Tasks</value>
|
<value>Better GI</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||||
<value>General</value>
|
<value>General</value>
|
||||||
@@ -2247,7 +2241,7 @@
|
|||||||
<value>File</value>
|
<value>File</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||||
<value>Process Linkage</value>
|
<value>InterProcess</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||||
<value>Run the software on the selected monitor</value>
|
<value>Run the software on the selected monitor</value>
|
||||||
@@ -2268,7 +2262,7 @@
|
|||||||
<value>Try to start Starward after the game is started for game duration statistics</value>
|
<value>Try to start Starward after the game is started for game duration statistics</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGamePlayTimeHeader" xml:space="preserve">
|
<data name="ViewPageLaunchGamePlayTimeHeader" xml:space="preserve">
|
||||||
<value>Game Hours Record</value>
|
<value>Hours Played</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameProcessHeader" xml:space="preserve">
|
<data name="ViewPageLaunchGameProcessHeader" xml:space="preserve">
|
||||||
<value>Progress</value>
|
<value>Progress</value>
|
||||||
@@ -2381,9 +2375,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>Wallpaper Image</value>
|
<value>Wallpaper Image</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>Using local images as the background</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>
|
||||||
@@ -2639,12 +2630,6 @@
|
|||||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||||
<value>Rate Snap Hutao</value>
|
<value>Rate Snap Hutao</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
|
||||||
<value>Change window theme</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
|
||||||
<value>Theme</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||||
<value>Contribute Translations</value>
|
<value>Contribute Translations</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2654,12 +2639,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>Webview2 Runtime</value>
|
<value>Webview2 Runtime</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
|
||||||
<value>Second Half</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
|
||||||
<value>First Half</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||||
<value>Artifact Set Combination</value>
|
<value>Artifact Set Combination</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2766,7 +2745,7 @@
|
|||||||
<value>Character Appearance Rate = Character Appearance in this Floor (only count for 1 if repeated) / Total Number of Abyss Record of this Floor</value>
|
<value>Character Appearance Rate = Character Appearance in this Floor (only count for 1 if repeated) / Total Number of Abyss Record of this Floor</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
|
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
|
||||||
<value>Character Usage Rate = Character Appearance in this Floor (only count for 1 if repeated) / Number of Player who Own this Character</value>
|
<value>Character Usage Rate = Character Appearance in this Floor (only count for 1 is repeated) / Number of Player who Own this Character</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
|
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
|
||||||
<value>Battle Statistics</value>
|
<value>Battle Statistics</value>
|
||||||
@@ -2922,7 +2901,7 @@
|
|||||||
<value>〓Event Duration〓.*?\d\.\d Available throughout the entirety of Version</value>
|
<value>〓Event Duration〓.*?\d\.\d Available throughout the entirety of Version</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||||
<value>(?:〓Event Duration〓|Event Wish Duration|【Availability Duration】|〓Discount Period〓).*?(\d\.\dAfter the Version update).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>(?:〓Event Duration〓|Event Wish Duration|【Availability Duration】).*?(\d\.\dAfter the Version update).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
<value>〓Update Maintenance Duration〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>〓Update Maintenance Duration〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
@@ -3074,9 +3053,6 @@
|
|||||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||||
<value>Character Event Wish-2</value>
|
<value>Character Event Wish-2</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
|
||||||
<value>Chronicled Wish</value>
|
|
||||||
</data>
|
|
||||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||||
<value>Beginners' Wish</value>
|
<value>Beginners' Wish</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>WebView2 Runtime tidak terdeteksi.</value>
|
<value>WebView2 Runtime tidak terdeteksi.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] Hotkey [{1}] gagal terdaftar</value>
|
|
||||||
</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>Ekspor</value>
|
<value>Ekspor</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -211,19 +199,19 @@
|
|||||||
<value>Pilih akun untuk memulai</value>
|
<value>Pilih akun untuk memulai</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlD" xml:space="preserve">
|
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlD" xml:space="preserve">
|
||||||
<value><color=#1E90FF>Prince</color>/<color=#FFB6C1>Princess</color></value>
|
<value><color=#1E90FF>王子</color>/<color=#FFB6C1>公主</color></value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlFirst" xml:space="preserve">
|
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlFirst" xml:space="preserve">
|
||||||
<value><color=#1E90FF>I</color>/<color=#FFB6C1>I</color></value>
|
<value><color=#1E90FF>我</color>/<color=#FFB6C1>我</color></value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
||||||
<value>Pengembara</value>
|
<value>Pengembara</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
||||||
<value><color=#1E90FF>He</color>/<color=#FFB6C1>She</color></value>
|
<value><color=#1E90FF>他</color>/<color=#FFB6C1>她</color></value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNameRealNameId1" xml:space="preserve">
|
<data name="MetadataSpecialNameRealNameId1" xml:space="preserve">
|
||||||
<value>Pengembara</value>
|
<value>流浪者</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelBindingAvatarPropertyWeaponAffixFormat" xml:space="preserve">
|
<data name="ModelBindingAvatarPropertyWeaponAffixFormat" xml:space="preserve">
|
||||||
<value>Perbaiki {0}</value>
|
<value>Perbaiki {0}</value>
|
||||||
@@ -525,7 +513,7 @@
|
|||||||
<value>Gelombang 4: Gelombang akan muncul hanya setelah membunuh semua musuh di gelombang sebelumnya</value>
|
<value>Gelombang 4: Gelombang akan muncul hanya setelah membunuh semua musuh di gelombang sebelumnya</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
||||||
<value>Tetapkan 4 Perampok Harta Karun di lapangan, langsung muncul kembali setelah mati. Total 12.</value>
|
<value>维持场上 4 个盗宝团怪物,击杀后立即替换,总数 12 个</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
||||||
<value>Silakan perbarui data tampilan.</value>
|
<value>Silakan perbarui data tampilan.</value>
|
||||||
@@ -780,19 +768,19 @@
|
|||||||
<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">
|
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
|
||||||
<value>Wallpaper Harian Bing</value>
|
<value>必应每日一图</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
||||||
<value>Wallpaper Harian Hutao</value>
|
<value>胡桃每日一图</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
||||||
<value>Wallpaper Resmi Peluncur Genshin</value>
|
<value>官方启动器壁纸</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
||||||
<value>Gambar Acak Lokal</value>
|
<value>本地随机图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
||||||
<value>Tanpa Gambar Latar</value>
|
<value>无背景图片</value>
|
||||||
</data>
|
</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>
|
||||||
@@ -852,7 +840,7 @@
|
|||||||
<value>Parametric Transformer telah siap</value>
|
<value>Parametric Transformer telah siap</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
||||||
<value>Izin hilang, tidak dapat mengatur Aktivitas Discord Anda.</value>
|
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
||||||
<value>Menjelajahi di Teyvat</value>
|
<value>Menjelajahi di Teyvat</value>
|
||||||
@@ -869,9 +857,6 @@
|
|||||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||||
<value>Event Wish Karakter</value>
|
<value>Event Wish Karakter</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>Wanderlust Invocation</value>
|
<value>Wanderlust Invocation</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1239,10 +1224,10 @@
|
|||||||
<value>Catatan Realtime Webhook URL</value>
|
<value>Catatan Realtime Webhook URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||||
<value>Anda memerlukan alat lain untuk mengembalikan loopback setelah dikecualikan</value>
|
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||||
<value>Konfirmasi untuk Mengonfigurasi Pengecualian Loopback</value>
|
<value>是否解除 Loopback 限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||||
<value>Mengimpor riwayat wish</value>
|
<value>Mengimpor riwayat wish</value>
|
||||||
@@ -1425,7 +1410,7 @@
|
|||||||
<value>Game Launcher</value>
|
<value>Game Launcher</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
||||||
<value>Tidak dapat mengurutkan dalam Mode Administrator</value>
|
<value>管理员模式下无法拖动排序</value>
|
||||||
</data>
|
</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>
|
||||||
@@ -1707,7 +1692,7 @@
|
|||||||
<value>Selesai</value>
|
<value>Selesai</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
||||||
<value>Stream respons tidak berisi tipe konten yang valid</value>
|
<value>响应内容不是有效的文件字节流</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
||||||
<value>Mengantre</value>
|
<value>Mengantre</value>
|
||||||
@@ -1926,16 +1911,16 @@
|
|||||||
<value>Tautan Berguna</value>
|
<value>Tautan Berguna</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||||
<value>Proxy Saat ini</value>
|
<value>当前代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||||
<value>Tidak ada Proxy</value>
|
<value>无代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||||
<value>Dikecualikan</value>
|
<value>已解除</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||||
<value>Konfigurasikan Pengecualian Loopback</value>
|
<value>解除 Loopback 限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
||||||
<value>Tetap berhubungan dengan kami</value>
|
<value>Tetap berhubungan dengan kami</value>
|
||||||
@@ -2226,10 +2211,10 @@
|
|||||||
<value>Argumen Awalan</value>
|
<value>Argumen Awalan</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
||||||
<value>Mulai Otomatis Antarmuka Pengguna yang Lebih Baik untuk tugas otomatis setelah game diluncurkan</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>Umum</value>
|
<value>Umum</value>
|
||||||
@@ -2373,16 +2358,13 @@
|
|||||||
<value>Backdrop Material</value>
|
<value>Backdrop Material</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
||||||
<value>Informasi Hak Cipta Gambar</value>
|
<value>图片版权信息</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
||||||
<value>Ubah sumber gambar latar, restart Snap Hutao untuk menerapkan perubahan</value>
|
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>Gambar Latar</value>
|
<value>背景图片</value>
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
|
||||||
</data>
|
</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>
|
||||||
@@ -2391,7 +2373,7 @@
|
|||||||
<value>Berkas Cache</value>
|
<value>Berkas Cache</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
||||||
<value>Hutao Passport</value>
|
<value>胡桃通行证</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
||||||
<value>Salin</value>
|
<value>Salin</value>
|
||||||
@@ -2586,10 +2568,10 @@
|
|||||||
<value>Website Resmi</value>
|
<value>Website Resmi</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
||||||
<value>Latar Belakang Kustom, format didukung 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>Buka Berkas Latar Belakang</value>
|
<value>打开背景图片文件夹</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
||||||
<value>Reset</value>
|
<value>Reset</value>
|
||||||
@@ -2601,10 +2583,10 @@
|
|||||||
<value>Setel ulang Sumber Daya Gambar</value>
|
<value>Setel ulang Sumber Daya Gambar</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
||||||
<value>Tambahkan Opsi Batasan FPS di Bagian Proses Peluncur Permainan</value>
|
<value>在启动游戏页面的进程部分加入解锁帧率限制选项</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
||||||
<value>Peluncur Permainan - Buka Limit FPS</value>
|
<value>启动游戏-解锁帧率限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
||||||
<value>Anda perlu memindahkan data di direktori secara manual, jika tidak, data pengguna baru akan dibuat.</value>
|
<value>Anda perlu memindahkan data di direktori secara manual, jika tidak, data pengguna baru akan dibuat.</value>
|
||||||
@@ -2639,12 +2621,6 @@
|
|||||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||||
<value>Beri Rating untuk Snap Hutao</value>
|
<value>Beri Rating untuk Snap Hutao</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>Kontribusi penerjemahan</value>
|
<value>Kontribusi penerjemahan</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2654,12 +2630,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>Webview2 Runtime</value>
|
<value>Webview2 Runtime</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>Kombinasi Set Artefak</value>
|
<value>Kombinasi Set Artefak</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2922,7 +2892,7 @@
|
|||||||
<value>〓Durasi Event〓.*?\d\.\d Tersedia selama versi ini</value>
|
<value>〓Durasi Event〓.*?\d\.\d Tersedia selama versi ini</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||||
<value>(?:〓Waktu Acara〓|Waktu Menginginkan|【Waktu Peluncuran】|〓Waktu Diskon〓).*?(\d\.\d Setelah Pembaruan Versi).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>(?:〓Durasi Event〓|Durasi Event Wish|【Ketersediaan DUrasi】).*?(\d\.\dSetelah pembaruan versi).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
<value>〓Durasi Pemeliharaan Pembaruan.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>〓Durasi Pemeliharaan Pembaruan.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
@@ -3074,9 +3044,6 @@
|
|||||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||||
<value>Event WIsh Karakter-2</value>
|
<value>Event WIsh Karakter-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>Wish Pemula</value>
|
<value>Wish Pemula</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>WebView2 ランタイムが検出されませんでした</value>
|
<value>WebView2 ランタイムが検出されませんでした</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
|
||||||
</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 +857,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>
|
||||||
@@ -1368,7 +1353,7 @@
|
|||||||
<value>クッキーを設定</value>
|
<value>クッキーを設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewFeedbackHeader" xml:space="preserve">
|
<data name="ViewFeedbackHeader" xml:space="preserve">
|
||||||
<value>フィードバックセンター</value>
|
<value>フィードバック センター</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewGachaLogHeader" xml:space="preserve">
|
<data name="ViewGachaLogHeader" xml:space="preserve">
|
||||||
<value>祈願履歴</value>
|
<value>祈願履歴</value>
|
||||||
@@ -2229,7 +2214,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>
|
||||||
@@ -2381,9 +2366,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景图片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||||
<value>イメージキャッシュはここに格納されます</value>
|
<value>イメージキャッシュはここに格納されます</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2505,7 +2487,7 @@
|
|||||||
<value>アチーブメント</value>
|
<value>アチーブメント</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
|
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
|
||||||
<value>リアルタイムノート</value>
|
<value>リアルタイムノート</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
|
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
|
||||||
<value>祈願履歴</value>
|
<value>祈願履歴</value>
|
||||||
@@ -2639,12 +2621,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>
|
||||||
@@ -2654,12 +2630,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>
|
||||||
@@ -2859,7 +2829,7 @@
|
|||||||
<value>QRコードでログイン</value>
|
<value>QRコードでログイン</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
|
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
|
||||||
<value>手動入力</value>
|
<value>手入力</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperationRefreshCookieAction" xml:space="preserve">
|
<data name="ViewUserCookieOperationRefreshCookieAction" xml:space="preserve">
|
||||||
<value>Cookie 再取得</value>
|
<value>Cookie 再取得</value>
|
||||||
@@ -2925,10 +2895,10 @@
|
|||||||
<value>(?:〓イベント期間〓|祈願期間|【開始日時】).*?(\d\.\dバージョンアップ完了後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>(?:〓イベント期間〓|祈願期間|【開始日時】).*?(\d\.\dバージョンアップ完了後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
<value>〓メンテナンス時間〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>〓更新日時〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTitle" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTitle" xml:space="preserve">
|
||||||
<value>Ver.\d\.\d.+正式リリース</value>
|
<value>Ver.\d\.\d 更新内容</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
|
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
|
||||||
<value>{0} 日後に開始</value>
|
<value>{0} 日後に開始</value>
|
||||||
@@ -3074,9 +3044,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>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>WebView2 런타임이 감지되지 않음</value>
|
<value>WebView2 런타임이 감지되지 않음</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
|
||||||
</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 +857,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 +2214,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>
|
||||||
@@ -2381,9 +2366,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景图片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||||
<value>여기에 저장된 이미지 캐시</value>
|
<value>여기에 저장된 이미지 캐시</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2639,12 +2621,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>
|
||||||
@@ -2654,12 +2630,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>
|
||||||
@@ -3074,9 +3044,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>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>O WebView2 Runtime não foi detectado</value>
|
<value>O WebView2 Runtime não foi detectado</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
|
||||||
</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>Exportar</value>
|
<value>Exportar</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -869,9 +857,6 @@
|
|||||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||||
<value>Evento de oração de personagem</value>
|
<value>Evento de oração de personagem</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>Invocação do Mochileiro</value>
|
<value>Invocação do Mochileiro</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1137,7 +1122,7 @@
|
|||||||
<value>Sorte média</value>
|
<value>Sorte média</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewControlStatisticsCardUpText" xml:space="preserve">
|
<data name="ViewControlStatisticsCardUpText" xml:space="preserve">
|
||||||
<value>Em destaque</value>
|
<value>Acima</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewControlStatisticsSegmentedItemContentPrediction" xml:space="preserve">
|
<data name="ViewControlStatisticsSegmentedItemContentPrediction" xml:space="preserve">
|
||||||
<value>Previsão</value>
|
<value>Previsão</value>
|
||||||
@@ -1155,7 +1140,7 @@
|
|||||||
<value>Planejamento</value>
|
<value>Planejamento</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDailyNoteHeader" xml:space="preserve">
|
<data name="ViewDailyNoteHeader" xml:space="preserve">
|
||||||
<value>Lembretes</value>
|
<value>Lembrete em tempo real</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDataHeader" xml:space="preserve">
|
<data name="ViewDataHeader" xml:space="preserve">
|
||||||
<value>Dados</value>
|
<value>Dados</value>
|
||||||
@@ -2049,7 +2034,7 @@
|
|||||||
<value>Visão geral</value>
|
<value>Visão geral</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
|
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
|
||||||
<value>Estatísticas globais</value>
|
<value>全球祈愿统计</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
|
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
|
||||||
<value>Arma</value>
|
<value>Arma</value>
|
||||||
@@ -2229,7 +2214,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>Geral</value>
|
<value>Geral</value>
|
||||||
@@ -2381,9 +2366,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景图片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" 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>
|
||||||
@@ -2639,12 +2621,6 @@
|
|||||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||||
<value>Avalie o Snap Hutao</value>
|
<value>Avalie o Snap Hutao</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>Contribuir com traduções</value>
|
<value>Contribuir com traduções</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2654,12 +2630,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>Webview2 Runtime</value>
|
<value>Webview2 Runtime</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>Combinação de conjuntos de artefatos</value>
|
<value>Combinação de conjuntos de artefatos</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2991,7 +2961,7 @@
|
|||||||
<value>Recompensa de comissão diária resgatada</value>
|
<value>Recompensa de comissão diária resgatada</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
|
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
|
||||||
<value>Estará cheio {0} às {1:HH:mm}</value>
|
<value>Estará cheio em {0} {1:HH:mm}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebDailyNoteHomeLocked" xml:space="preserve">
|
<data name="WebDailyNoteHomeLocked" xml:space="preserve">
|
||||||
<value>Bule de Relachá não desbloqueado</value>
|
<value>Bule de Relachá não desbloqueado</value>
|
||||||
@@ -3074,9 +3044,6 @@
|
|||||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||||
<value>Evento de oração de personagem-2</value>
|
<value>Evento de oração de personagem-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>Oração de Novatos</value>
|
<value>Oração de Novatos</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -2381,9 +2381,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景图片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||||
<value>图片缓存 在此处存放</value>
|
<value>图片缓存 在此处存放</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>Среда выполнения WebView2 не обнаружена</value>
|
<value>Среда выполнения WebView2 не обнаружена</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
|
||||||
</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 +857,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 +2214,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>
|
||||||
@@ -2381,9 +2366,6 @@
|
|||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景图片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||||
<value>图片缓存 在此处存放</value>
|
<value>图片缓存 在此处存放</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2639,12 +2621,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>
|
||||||
@@ -2654,12 +2630,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>Webview2 Runtime</value>
|
<value>Webview2 Runtime</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>
|
||||||
@@ -3074,9 +3044,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>
|
||||||
|
|||||||
@@ -186,18 +186,6 @@
|
|||||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||||
<value>未檢測到 WebView2 運行時</value>
|
<value>未檢測到 WebView2 運行時</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
|
||||||
<value>[{0}] 鍵盤快速鍵 [{1}] 註冊失敗</value>
|
|
||||||
</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>
|
||||||
@@ -217,7 +205,7 @@
|
|||||||
<value><color=#1E90FF>我</color>/<color=#FFB6C1>我</color></value>
|
<value><color=#1E90FF>我</color>/<color=#FFB6C1>我</color></value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
||||||
<value>旅行者</value>
|
<value>旅人</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
||||||
<value><color=#1E90FF>他</color>/<color=#FFB6C1>她</color></value>
|
<value><color=#1E90FF>他</color>/<color=#FFB6C1>她</color></value>
|
||||||
@@ -525,7 +513,7 @@
|
|||||||
<value>第四波:擊敗所有怪物,下一波才會出現</value>
|
<value>第四波:擊敗所有怪物,下一波才會出現</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
||||||
<value>維持場上 4 個盜寶團怪物,擊殺後立即替換,總數 12 個</value>
|
<value>维持场上 4 个盗宝团怪物,击杀后立即替换,总数 12 个</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
||||||
<value>請更新角色櫥窗數據</value>
|
<value>請更新角色櫥窗數據</value>
|
||||||
@@ -780,19 +768,19 @@
|
|||||||
<value>角色櫥窗:{0:MM-dd HH:mm}</value>
|
<value>角色櫥窗:{0:MM-dd HH:mm}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
|
||||||
<value>Bing每日一圖</value>
|
<value>必应每日一图</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
||||||
<value>胡桃每日一圖</value>
|
<value>胡桃每日一图</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
||||||
<value>官方啟動器壁紙</value>
|
<value>官方启动器壁纸</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
||||||
<value>本地隨機圖片</value>
|
<value>本地随机图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
||||||
<value>無背景圖片</value>
|
<value>无背景图片</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
||||||
<value>保存養成計劃狀態失敗</value>
|
<value>保存養成計劃狀態失敗</value>
|
||||||
@@ -852,7 +840,7 @@
|
|||||||
<value>參量質變儀已準備完成</value>
|
<value>參量質變儀已準備完成</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
||||||
<value>權限不足,將無法為您設定 Discord Activity 狀態</value>
|
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
||||||
<value>正在提瓦特大陸中探索</value>
|
<value>正在提瓦特大陸中探索</value>
|
||||||
@@ -869,9 +857,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>
|
||||||
@@ -1239,7 +1224,7 @@
|
|||||||
<value>即時便箋 Webhook Url</value>
|
<value>即時便箋 Webhook Url</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||||
<value>解除限制後需使用其他工具恢復限制</value>
|
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||||
<value>是否解除 Loopback 限制</value>
|
<value>是否解除 Loopback 限制</value>
|
||||||
@@ -1425,7 +1410,7 @@
|
|||||||
<value>啟動遊戲</value>
|
<value>啟動遊戲</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
||||||
<value>管理員模式下無法拖動排序</value>
|
<value>管理员模式下无法拖动排序</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
|
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
|
||||||
<value>存檔 [{0}] 添加成功</value>
|
<value>存檔 [{0}] 添加成功</value>
|
||||||
@@ -1707,7 +1692,7 @@
|
|||||||
<value>完成</value>
|
<value>完成</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
||||||
<value>回應內容不是有效的檔案位元組</value>
|
<value>响应内容不是有效的文件字节流</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
||||||
<value>待處理</value>
|
<value>待處理</value>
|
||||||
@@ -1926,16 +1911,16 @@
|
|||||||
<value>常用連結</value>
|
<value>常用連結</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||||
<value>當前代理</value>
|
<value>当前代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||||
<value>無代理</value>
|
<value>无代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||||
<value>已解除</value>
|
<value>已解除</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||||
<value>是否解除 Loopback 限制</value>
|
<value>解除 Loopback 限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
||||||
<value>與我們密切聯繫</value>
|
<value>與我們密切聯繫</value>
|
||||||
@@ -2226,10 +2211,10 @@
|
|||||||
<value>啟動參數</value>
|
<value>啟動參數</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
||||||
<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 +2232,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>
|
||||||
@@ -2373,16 +2358,13 @@
|
|||||||
<value>背景材質</value>
|
<value>背景材質</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
||||||
<value>圖片版權訊息</value>
|
<value>图片版权信息</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
||||||
<value>更改視窗的背景圖片來源,重啟胡桃以盡快生效</value>
|
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||||
<value>背景圖片</value>
|
<value>背景图片</value>
|
||||||
</data>
|
|
||||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
|
||||||
<value>當前背景為本地圖片,如遇版權問題由用戶個人負責</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||||
<value>圖片暫存存放在此</value>
|
<value>圖片暫存存放在此</value>
|
||||||
@@ -2391,7 +2373,7 @@
|
|||||||
<value>暫存檔案夾</value>
|
<value>暫存檔案夾</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
||||||
<value>胡桃通行證</value>
|
<value>胡桃通行证</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
||||||
<value>複製</value>
|
<value>複製</value>
|
||||||
@@ -2586,10 +2568,10 @@
|
|||||||
<value>前往官網</value>
|
<value>前往官網</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
||||||
<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>打開背景圖片資料夾</value>
|
<value>打开背景图片文件夹</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
||||||
<value>重設</value>
|
<value>重設</value>
|
||||||
@@ -2601,10 +2583,10 @@
|
|||||||
<value>重設圖片資源</value>
|
<value>重設圖片資源</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
||||||
<value>在啟動遊戲頁面的程序部分加入解鎖幀率限制選項</value>
|
<value>在启动游戏页面的进程部分加入解锁帧率限制选项</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
||||||
<value>啟動遊戲-解鎖幀率限制</value>
|
<value>启动游戏-解锁帧率限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
||||||
<value>更改目錄后需要手動移動目錄内的數據,否則會重新創建用戶數據</value>
|
<value>更改目錄后需要手動移動目錄内的數據,否則會重新創建用戶數據</value>
|
||||||
@@ -2639,12 +2621,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>
|
||||||
@@ -2654,12 +2630,6 @@
|
|||||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||||
<value>WebView 2 運行時</value>
|
<value>WebView 2 運行時</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>
|
||||||
@@ -2922,7 +2892,7 @@
|
|||||||
<value>〓活動時間〓.*?\d\.\d版本期間持續開放</value>
|
<value>〓活動時間〓.*?\d\.\d版本期間持續開放</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||||
<value>(?:〓活動時間〓|祈願時間|【上架時間】|〓折扣時間〓).*?(\d\.\d版本更新後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>(?:〓活動時間〓|祈願時間|【上架時間】).*?(\d\.\d版本更新後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
<value>〓更新時間〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
<value>〓更新時間〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
@@ -3074,9 +3044,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>
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ internal sealed class GachaTypeComparer : IComparer<GachaType>
|
|||||||
KeyValuePair.Create(GachaType.ActivityAvatar, 0),
|
KeyValuePair.Create(GachaType.ActivityAvatar, 0),
|
||||||
KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1),
|
KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1),
|
||||||
KeyValuePair.Create(GachaType.ActivityWeapon, 2),
|
KeyValuePair.Create(GachaType.ActivityWeapon, 2),
|
||||||
KeyValuePair.Create(GachaType.ActivityCity, 3),
|
KeyValuePair.Create(GachaType.Standard, 3),
|
||||||
KeyValuePair.Create(GachaType.Standard, 4),
|
KeyValuePair.Create(GachaType.NewBie, 4),
|
||||||
KeyValuePair.Create(GachaType.NewBie, 5),
|
KeyValuePair.Create(GachaType.ActivityCity, 5),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -38,10 +38,6 @@ internal sealed class PullPrediction
|
|||||||
typedWishSummary.PredictedPullLeftToOrange = result.PredictedPullLeftToOrange;
|
typedWishSummary.PredictedPullLeftToOrange = result.PredictedPullLeftToOrange;
|
||||||
typedWishSummary.IsPredictPullAvailable = true;
|
typedWishSummary.IsPredictPullAvailable = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
await barrier.SignalAndWaitAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PredictResult PredictCore(List<PullCount> distribution, TypedWishSummary typedWishSummary)
|
private static PredictResult PredictCore(List<PullCount> distribution, TypedWishSummary typedWishSummary)
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProv
|
|||||||
{
|
{
|
||||||
ReadOnlySpan<byte> span = stream.ToArray();
|
ReadOnlySpan<byte> span = stream.ToArray();
|
||||||
ReadOnlySpan<byte> match = isOversea
|
ReadOnlySpan<byte> match = isOversea
|
||||||
? "https://gs.hoyoverse.com/genshin/event/e20190909gacha-v3/index.html"u8
|
? "https://gs.hoyoverse.com/genshin/event/e20190909gacha-v2/index.html"u8
|
||||||
: "https://webstatic.mihoyo.com/hk4e/event/e20190909gacha-v3/index.html"u8;
|
: "https://webstatic.mihoyo.com/hk4e/event/e20190909gacha-v2/index.html"u8;
|
||||||
|
|
||||||
int index = span.LastIndexOf(match);
|
int index = span.LastIndexOf(match);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ internal sealed class LaunchOptions : DbStoreOptions
|
|||||||
|
|
||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
get => GetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, false);
|
get => GetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, true);
|
||||||
set => SetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, value);
|
set => SetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ internal sealed class LaunchStatus
|
|||||||
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
public static LaunchStatus FromUnlockerContext(GameFpsUnlockerContext unlockerState)
|
public static LaunchStatus FromUnlockStatus(UnlockerStatus unlockerStatus)
|
||||||
{
|
{
|
||||||
if (unlockerState.FindModuleResult == FindModuleResult.Ok)
|
if (unlockerStatus.FindModuleState == FindModuleResult.Ok)
|
||||||
{
|
{
|
||||||
return new(LaunchPhase.UnlockFpsSucceed, SH.ServiceGameLaunchPhaseUnlockFpsSucceed);
|
return new(LaunchPhase.UnlockFpsSucceed, SH.ServiceGameLaunchPhaseUnlockFpsSucceed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ internal sealed class LaunchExecutionBetterGenshinImpactAutomationHandlder : ILa
|
|||||||
{
|
{
|
||||||
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
||||||
{
|
{
|
||||||
if (!context.Process.HasExited && context.Options.UseBetterGenshinImpactAutomation)
|
if (context.Options.UseBetterGenshinImpactAutomation)
|
||||||
{
|
{
|
||||||
context.Logger.LogInformation("Using BetterGI to automate gameplay");
|
context.Logger.LogInformation("Using BetterGI to automate gameplay");
|
||||||
await LaunchBetterGenshinImpactAsync(context).ConfigureAwait(false);
|
await LaunchBetterGenshinImpactAsync(context).ConfigureAwait(false);
|
||||||
@@ -26,12 +26,10 @@ internal sealed class LaunchExecutionBetterGenshinImpactAutomationHandlder : ILa
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
context.Logger.LogInformation("Waiting game window to be ready");
|
context.Logger.LogInformation("Waiting game window to be ready");
|
||||||
|
context.Process.WaitForInputIdle();
|
||||||
SpinWait.SpinUntil(() => context.Process.MainWindowHandle != IntPtr.Zero);
|
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
{
|
{
|
||||||
context.Logger.LogInformation("Failed to get game window handle");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,18 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Launching.Handler;
|
namespace Snap.Hutao.Service.Game.Launching.Handler;
|
||||||
|
|
||||||
internal sealed class LaunchExecutionEnsureGameNotRunningHandler : ILaunchExecutionDelegateHandler
|
internal sealed class LaunchExecutionEnsureGameNotRunningHandler : ILaunchExecutionDelegateHandler
|
||||||
{
|
{
|
||||||
public static bool IsGameRunning([NotNullWhen(true)] out Process? runningProcess)
|
public static bool IsGameRunning([NotNullWhen(true)] out System.Diagnostics.Process? runningProcess)
|
||||||
{
|
{
|
||||||
int currentSessionId = Process.GetCurrentProcess().SessionId;
|
|
||||||
|
|
||||||
// GetProcesses once and manually loop is O(n)
|
// GetProcesses once and manually loop is O(n)
|
||||||
foreach (ref readonly Process process in Process.GetProcesses().AsSpan())
|
foreach (ref readonly System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses().AsSpan())
|
||||||
{
|
{
|
||||||
if (string.Equals(process.ProcessName, GameConstants.YuanShenProcessName, StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(process.ProcessName, GameConstants.YuanShenProcessName, StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(process.ProcessName, GameConstants.GenshinImpactProcessName, StringComparison.OrdinalIgnoreCase))
|
string.Equals(process.ProcessName, GameConstants.GenshinImpactProcessName, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (process.SessionId != currentSessionId)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
runningProcess = process;
|
runningProcess = process;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -33,7 +24,7 @@ internal sealed class LaunchExecutionEnsureGameNotRunningHandler : ILaunchExecut
|
|||||||
|
|
||||||
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
||||||
{
|
{
|
||||||
if (IsGameRunning(out Process? process))
|
if (IsGameRunning(out System.Diagnostics.Process? process))
|
||||||
{
|
{
|
||||||
context.Logger.LogInformation("Game process detected, id: {Id}", process.Id);
|
context.Logger.LogInformation("Game process detected, id: {Id}", process.Id);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ internal sealed class LaunchExecutionStarwardPlayTimeStatisticsHandler : ILaunch
|
|||||||
{
|
{
|
||||||
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
||||||
{
|
{
|
||||||
if (!context.Process.HasExited && context.Options.UseStarwardPlayTimeStatistics)
|
if (context.Options.UseStarwardPlayTimeStatistics)
|
||||||
{
|
{
|
||||||
context.Logger.LogInformation("Using Starward to count game time");
|
context.Logger.LogInformation("Using Starward to count game time");
|
||||||
await LaunchStarwardForPlayTimeStatisticsAsync(context).ConfigureAwait(false);
|
await LaunchStarwardForPlayTimeStatisticsAsync(context).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -18,17 +18,14 @@ internal sealed class LaunchExecutionUnlockFpsHandler : ILaunchExecutionDelegate
|
|||||||
context.Progress.Report(new(LaunchPhase.UnlockingFps, SH.ServiceGameLaunchPhaseUnlockingFps));
|
context.Progress.Report(new(LaunchPhase.UnlockingFps, SH.ServiceGameLaunchPhaseUnlockingFps));
|
||||||
|
|
||||||
IProgressFactory progressFactory = context.ServiceProvider.GetRequiredService<IProgressFactory>();
|
IProgressFactory progressFactory = context.ServiceProvider.GetRequiredService<IProgressFactory>();
|
||||||
IProgress<GameFpsUnlockerContext> progress = progressFactory.CreateForMainThread<GameFpsUnlockerContext>(c => context.Progress.Report(LaunchStatus.FromUnlockerContext(c)));
|
IProgress<UnlockerStatus> progress = progressFactory.CreateForMainThread<UnlockerStatus>(status => context.Progress.Report(LaunchStatus.FromUnlockStatus(status)));
|
||||||
GameFpsUnlocker unlocker = new(context.ServiceProvider, context.Process, new(100, 20000, 3000), progress);
|
GameFpsUnlocker unlocker = context.ServiceProvider.CreateInstance<GameFpsUnlocker>(context.Process);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (await unlocker.UnlockAsync(context.CancellationToken).ConfigureAwait(false))
|
await unlocker.UnlockAsync(new(100, 20000, 3000), progress, context.CancellationToken).ConfigureAwait(false);
|
||||||
{
|
|
||||||
unlocker.PostUnlockAsync(context.CancellationToken).SafeForget();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (InvalidOperationException ex)
|
||||||
{
|
{
|
||||||
context.Logger.LogCritical(ex, "Unlocking FPS failed");
|
context.Logger.LogCritical(ex, "Unlocking FPS failed");
|
||||||
|
|
||||||
|
|||||||
@@ -24,25 +24,25 @@ internal sealed class LaunchExecutionInvoker
|
|||||||
handlers.Enqueue(new LaunchExecutionGameProcessInitializationHandler());
|
handlers.Enqueue(new LaunchExecutionGameProcessInitializationHandler());
|
||||||
handlers.Enqueue(new LaunchExecutionSetDiscordActivityHandler());
|
handlers.Enqueue(new LaunchExecutionSetDiscordActivityHandler());
|
||||||
handlers.Enqueue(new LaunchExecutionGameProcessStartHandler());
|
handlers.Enqueue(new LaunchExecutionGameProcessStartHandler());
|
||||||
handlers.Enqueue(new LaunchExecutionUnlockFpsHandler());
|
|
||||||
handlers.Enqueue(new LaunchExecutionStarwardPlayTimeStatisticsHandler());
|
handlers.Enqueue(new LaunchExecutionStarwardPlayTimeStatisticsHandler());
|
||||||
handlers.Enqueue(new LaunchExecutionBetterGenshinImpactAutomationHandlder());
|
handlers.Enqueue(new LaunchExecutionBetterGenshinImpactAutomationHandlder());
|
||||||
|
handlers.Enqueue(new LaunchExecutionUnlockFpsHandler());
|
||||||
handlers.Enqueue(new LaunchExecutionGameProcessExitHandler());
|
handlers.Enqueue(new LaunchExecutionGameProcessExitHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<LaunchExecutionResult> InvokeAsync(LaunchExecutionContext context)
|
public async ValueTask<LaunchExecutionResult> InvokeAsync(LaunchExecutionContext context)
|
||||||
{
|
{
|
||||||
await RecursiveInvokeHandlerAsync(context).ConfigureAwait(false);
|
await InvokeHandlerAsync(context).ConfigureAwait(false);
|
||||||
return context.Result;
|
return context.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask<LaunchExecutionContext> RecursiveInvokeHandlerAsync(LaunchExecutionContext context)
|
private async ValueTask<LaunchExecutionContext> InvokeHandlerAsync(LaunchExecutionContext context)
|
||||||
{
|
{
|
||||||
if (handlers.TryDequeue(out ILaunchExecutionDelegateHandler? handler))
|
if (handlers.TryDequeue(out ILaunchExecutionDelegateHandler? handler))
|
||||||
{
|
{
|
||||||
string typeName = TypeNameHelper.GetTypeDisplayName(handler, false);
|
string typeName = TypeNameHelper.GetTypeDisplayName(handler, false);
|
||||||
context.Logger.LogInformation("Handler [{Handler}] begin execution", typeName);
|
context.Logger.LogInformation("Handler [{Handler}] begin execution", typeName);
|
||||||
await handler.OnExecutionAsync(context, () => RecursiveInvokeHandlerAsync(context)).ConfigureAwait(false);
|
await handler.OnExecutionAsync(context, () => InvokeHandlerAsync(context)).ConfigureAwait(false);
|
||||||
context.Logger.LogInformation("Handler [{Handler}] end execution", typeName);
|
context.Logger.LogInformation("Handler [{Handler}] end execution", typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
|
||||||
using Snap.Hutao.Win32.Foundation;
|
|
||||||
using Snap.Hutao.Win32.Memory;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using static Snap.Hutao.Win32.Kernel32;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
|
||||||
|
|
||||||
internal static class GameFpsAddress
|
|
||||||
{
|
|
||||||
#pragma warning disable SA1310
|
|
||||||
private const byte ASM_CALL = 0xE8;
|
|
||||||
private const byte ASM_JMP = 0xE9;
|
|
||||||
#pragma warning restore SA1310
|
|
||||||
|
|
||||||
public static unsafe void UnsafeFindFpsAddress(GameFpsUnlockerContext state, in RequiredGameModule requiredGameModule)
|
|
||||||
{
|
|
||||||
bool readOk = UnsafeReadModulesMemory(state.GameProcess, requiredGameModule, out VirtualMemory localMemory);
|
|
||||||
HutaoException.ThrowIfNot(readOk, HutaoExceptionKind.GameFpsUnlockingFailed, SH.ServiceGameUnlockerReadModuleMemoryCopyVirtualMemoryFailed);
|
|
||||||
|
|
||||||
using (localMemory)
|
|
||||||
{
|
|
||||||
int offset = IndexOfPattern(localMemory.AsSpan()[(int)requiredGameModule.UnityPlayer.Size..]);
|
|
||||||
HutaoException.ThrowIfNot(offset >= 0, HutaoExceptionKind.GameFpsUnlockingFailed, SH.ServiceGameUnlockerInterestedPatternNotFound);
|
|
||||||
|
|
||||||
byte* pLocalMemory = (byte*)localMemory.Pointer;
|
|
||||||
ref readonly Module unityPlayer = ref requiredGameModule.UnityPlayer;
|
|
||||||
ref readonly Module userAssembly = ref requiredGameModule.UserAssembly;
|
|
||||||
|
|
||||||
nuint localMemoryUnityPlayerAddress = (nuint)pLocalMemory;
|
|
||||||
nuint localMemoryUserAssemblyAddress = localMemoryUnityPlayerAddress + unityPlayer.Size;
|
|
||||||
|
|
||||||
nuint rip = localMemoryUserAssemblyAddress + (uint)offset;
|
|
||||||
rip += 5U;
|
|
||||||
rip += (nuint)(*(int*)(rip + 2U) + 6);
|
|
||||||
|
|
||||||
nuint address = userAssembly.Address + (rip - localMemoryUserAssemblyAddress);
|
|
||||||
|
|
||||||
nuint ptr = 0;
|
|
||||||
SpinWait.SpinUntil(() => UnsafeReadProcessMemory(state.GameProcess, address, out ptr) && ptr != 0);
|
|
||||||
|
|
||||||
rip = ptr - unityPlayer.Address + localMemoryUnityPlayerAddress;
|
|
||||||
|
|
||||||
while (*(byte*)rip is ASM_CALL or ASM_JMP)
|
|
||||||
{
|
|
||||||
rip += (nuint)(*(int*)(rip + 1) + 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
nuint localMemoryActualAddress = rip + *(uint*)(rip + 2) + 6;
|
|
||||||
nuint actualOffset = localMemoryActualAddress - localMemoryUnityPlayerAddress;
|
|
||||||
state.FpsAddress = unityPlayer.Address + actualOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int IndexOfPattern(in ReadOnlySpan<byte> memory)
|
|
||||||
{
|
|
||||||
// B9 3C 00 00 00 FF 15
|
|
||||||
ReadOnlySpan<byte> part = [0xB9, 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x15];
|
|
||||||
return memory.IndexOf(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe bool UnsafeReadModulesMemory(Process process, in RequiredGameModule moduleEntryInfo, out VirtualMemory memory)
|
|
||||||
{
|
|
||||||
ref readonly Module unityPlayer = ref moduleEntryInfo.UnityPlayer;
|
|
||||||
ref readonly Module userAssembly = ref moduleEntryInfo.UserAssembly;
|
|
||||||
|
|
||||||
memory = new VirtualMemory(unityPlayer.Size + userAssembly.Size);
|
|
||||||
return ReadProcessMemory(process.Handle, (void*)unityPlayer.Address, memory.AsSpan()[..(int)unityPlayer.Size], out _)
|
|
||||||
&& ReadProcessMemory(process.Handle, (void*)userAssembly.Address, memory.AsSpan()[(int)unityPlayer.Size..], out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe bool UnsafeReadProcessMemory(Process process, nuint baseAddress, out nuint value)
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
bool result = ReadProcessMemory((HANDLE)process.Handle, (void*)baseAddress, ref value, out _);
|
|
||||||
HutaoException.ThrowIfNot(result, HutaoExceptionKind.GameFpsUnlockingFailed, SH.ServiceGameUnlockerReadProcessMemoryPointerAddressFailed);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
// 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.ExceptionService;
|
using Snap.Hutao.Core.Diagnostics;
|
||||||
using Snap.Hutao.Win32.Foundation;
|
using Snap.Hutao.Win32.Foundation;
|
||||||
using System.Diagnostics;
|
using Snap.Hutao.Win32.Memory;
|
||||||
|
using Snap.Hutao.Win32.System.ProcessStatus;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using static Snap.Hutao.Win32.Kernel32;
|
using static Snap.Hutao.Win32.Kernel32;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
namespace Snap.Hutao.Service.Game.Unlocker;
|
||||||
@@ -15,55 +17,255 @@ namespace Snap.Hutao.Service.Game.Unlocker;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class GameFpsUnlocker : IGameFpsUnlocker
|
internal sealed class GameFpsUnlocker : IGameFpsUnlocker
|
||||||
{
|
{
|
||||||
|
private readonly System.Diagnostics.Process gameProcess;
|
||||||
private readonly LaunchOptions launchOptions;
|
private readonly LaunchOptions launchOptions;
|
||||||
private readonly GameFpsUnlockerContext context = new();
|
private readonly UnlockerStatus status = new();
|
||||||
|
|
||||||
public GameFpsUnlocker(IServiceProvider serviceProvider, Process gameProcess, in UnlockTimingOptions options, IProgress<GameFpsUnlockerContext> progress)
|
/// <summary>
|
||||||
|
/// 构造一个新的 <see cref="GameFpsUnlocker"/> 对象,
|
||||||
|
/// 每个解锁器只能解锁一次原神的进程,
|
||||||
|
/// 再次解锁需要重新创建对象
|
||||||
|
/// <para/>
|
||||||
|
/// 解锁器需要在管理员模式下才能正确的完成解锁操作,
|
||||||
|
/// 非管理员模式不能解锁
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceProvider">服务提供器</param>
|
||||||
|
/// <param name="gameProcess">游戏进程</param>
|
||||||
|
public GameFpsUnlocker(IServiceProvider serviceProvider, System.Diagnostics.Process gameProcess)
|
||||||
{
|
{
|
||||||
launchOptions = serviceProvider.GetRequiredService<LaunchOptions>();
|
launchOptions = serviceProvider.GetRequiredService<LaunchOptions>();
|
||||||
|
this.gameProcess = gameProcess;
|
||||||
context.GameProcess = gameProcess;
|
|
||||||
context.TimingOptions = options;
|
|
||||||
context.Progress = progress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<bool> UnlockAsync(CancellationToken token = default)
|
public async ValueTask UnlockAsync(UnlockTimingOptions options, IProgress<UnlockerStatus> progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
HutaoException.ThrowIfNot(context.IsUnlockerValid, HutaoExceptionKind.GameFpsUnlockingFailed, "This Unlocker is invalid");
|
Verify.Operation(status.IsUnlockerValid, "This Unlocker is invalid");
|
||||||
(FindModuleResult result, RequiredGameModule gameModule) = await GameProcessModule.FindModuleAsync(context).ConfigureAwait(false);
|
|
||||||
HutaoException.ThrowIfNot(result != FindModuleResult.TimeLimitExeeded, HutaoExceptionKind.GameFpsUnlockingFailed, SH.ServiceGameUnlockerFindModuleTimeLimitExeeded);
|
|
||||||
HutaoException.ThrowIfNot(result != FindModuleResult.NoModuleFound, HutaoExceptionKind.GameFpsUnlockingFailed, SH.ServiceGameUnlockerFindModuleNoModuleFound);
|
|
||||||
|
|
||||||
GameFpsAddress.UnsafeFindFpsAddress(context, gameModule);
|
(FindModuleResult result, GameModule moduleEntryInfo) = await FindModuleAsync(options.FindModuleDelay, options.FindModuleLimit).ConfigureAwait(false);
|
||||||
context.Report();
|
Verify.Operation(result != FindModuleResult.TimeLimitExeeded, SH.ServiceGameUnlockerFindModuleTimeLimitExeeded);
|
||||||
return context.FpsAddress != 0U;
|
Verify.Operation(result != FindModuleResult.NoModuleFound, SH.ServiceGameUnlockerFindModuleNoModuleFound);
|
||||||
|
|
||||||
|
// Read UnityPlayer.dll
|
||||||
|
UnsafeFindFpsAddress(moduleEntryInfo);
|
||||||
|
progress.Report(status);
|
||||||
|
|
||||||
|
// When player switch between scenes, we have to re adjust the fps
|
||||||
|
// So we keep a loop here
|
||||||
|
await LoopAdjustFpsAsync(options.AdjustFpsDelay, progress, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask PostUnlockAsync(CancellationToken token = default)
|
private static unsafe bool UnsafeReadModulesMemory(System.Diagnostics.Process process, in GameModule moduleEntryInfo, out VirtualMemory memory)
|
||||||
{
|
{
|
||||||
using (PeriodicTimer timer = new(context.TimingOptions.AdjustFpsDelay))
|
ref readonly Module unityPlayer = ref moduleEntryInfo.UnityPlayer;
|
||||||
|
ref readonly Module userAssembly = ref moduleEntryInfo.UserAssembly;
|
||||||
|
|
||||||
|
memory = new VirtualMemory(unityPlayer.Size + userAssembly.Size);
|
||||||
|
return ReadProcessMemory(process.Handle, (void*)unityPlayer.Address, memory.AsSpan()[..(int)unityPlayer.Size], out _)
|
||||||
|
&& ReadProcessMemory(process.Handle, (void*)userAssembly.Address, memory.AsSpan()[(int)unityPlayer.Size..], out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe bool UnsafeReadProcessMemory(System.Diagnostics.Process process, nuint baseAddress, out nuint value)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
bool result = ReadProcessMemory((HANDLE)process.Handle, (void*)baseAddress, ref value, out _);
|
||||||
|
Verify.Operation(result, SH.ServiceGameUnlockerReadProcessMemoryPointerAddressFailed);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe bool UnsafeWriteProcessMemory(System.Diagnostics.Process process, nuint baseAddress, int value)
|
||||||
|
{
|
||||||
|
return WriteProcessMemory((HANDLE)process.Handle, (void*)baseAddress, ref value, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe FindModuleResult UnsafeTryFindModule(in HANDLE hProcess, in ReadOnlySpan<char> moduleName, out Module module)
|
||||||
|
{
|
||||||
|
HMODULE[] buffer = new HMODULE[128];
|
||||||
|
if (!K32EnumProcessModules(hProcess, buffer, out uint actualSize))
|
||||||
|
{
|
||||||
|
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualSize == 0)
|
||||||
|
{
|
||||||
|
module = default!;
|
||||||
|
return FindModuleResult.NoModuleFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ref readonly HMODULE hModule in buffer.AsSpan()[..(int)(actualSize / sizeof(HMODULE))])
|
||||||
|
{
|
||||||
|
char[] baseName = new char[256];
|
||||||
|
|
||||||
|
if (K32GetModuleBaseNameW(hProcess, hModule, baseName) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed (char* lpBaseName = baseName)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> szModuleName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(lpBaseName);
|
||||||
|
if (!szModuleName.SequenceEqual(moduleName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!K32GetModuleInformation(hProcess, hModule, out MODULEINFO moduleInfo))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
module = new((nuint)moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage);
|
||||||
|
return FindModuleResult.Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
module = default;
|
||||||
|
return FindModuleResult.ModuleNotLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int IndexOfPattern(in ReadOnlySpan<byte> memory)
|
||||||
|
{
|
||||||
|
// B9 3C 00 00 00 FF 15
|
||||||
|
ReadOnlySpan<byte> part = [0xB9, 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x15];
|
||||||
|
return memory.IndexOf(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FindModuleResult UnsafeGetGameModuleInfo(in HANDLE hProcess, out GameModule info)
|
||||||
|
{
|
||||||
|
FindModuleResult unityPlayerResult = UnsafeTryFindModule(hProcess, "UnityPlayer.dll", out Module unityPlayer);
|
||||||
|
FindModuleResult userAssemblyResult = UnsafeTryFindModule(hProcess, "UserAssembly.dll", out Module userAssembly);
|
||||||
|
|
||||||
|
if (unityPlayerResult == FindModuleResult.Ok && userAssemblyResult == FindModuleResult.Ok)
|
||||||
|
{
|
||||||
|
info = new(unityPlayer, userAssembly);
|
||||||
|
return FindModuleResult.Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unityPlayerResult == FindModuleResult.NoModuleFound && userAssemblyResult == FindModuleResult.NoModuleFound)
|
||||||
|
{
|
||||||
|
info = default;
|
||||||
|
return FindModuleResult.NoModuleFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = default;
|
||||||
|
return FindModuleResult.ModuleNotLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<ValueResult<FindModuleResult, GameModule>> FindModuleAsync(TimeSpan findModuleDelay, TimeSpan findModuleLimit)
|
||||||
|
{
|
||||||
|
ValueStopwatch watch = ValueStopwatch.StartNew();
|
||||||
|
using (PeriodicTimer timer = new(findModuleDelay))
|
||||||
|
{
|
||||||
|
while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
FindModuleResult result = UnsafeGetGameModuleInfo((HANDLE)gameProcess.Handle, out GameModule gameModule);
|
||||||
|
if (result == FindModuleResult.Ok)
|
||||||
|
{
|
||||||
|
return new(FindModuleResult.Ok, gameModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == FindModuleResult.NoModuleFound)
|
||||||
|
{
|
||||||
|
return new(FindModuleResult.NoModuleFound, default);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watch.GetElapsedTime() > findModuleLimit)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(FindModuleResult.TimeLimitExeeded, default);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask LoopAdjustFpsAsync(TimeSpan adjustFpsDelay, IProgress<UnlockerStatus> progress, CancellationToken token)
|
||||||
|
{
|
||||||
|
using (PeriodicTimer timer = new(adjustFpsDelay))
|
||||||
{
|
{
|
||||||
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
if (!context.GameProcess.HasExited && context.FpsAddress != 0U)
|
if (!gameProcess.HasExited && status.FpsAddress != 0U)
|
||||||
{
|
{
|
||||||
UnsafeWriteProcessMemory(context.GameProcess, context.FpsAddress, launchOptions.TargetFps);
|
UnsafeWriteProcessMemory(gameProcess, status.FpsAddress, launchOptions.TargetFps);
|
||||||
context.Report();
|
progress.Report(status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.IsUnlockerValid = false;
|
status.IsUnlockerValid = false;
|
||||||
context.FpsAddress = 0;
|
status.FpsAddress = 0;
|
||||||
context.Report();
|
progress.Report(status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe bool UnsafeWriteProcessMemory(Process process, nuint baseAddress, int value)
|
private unsafe void UnsafeFindFpsAddress(in GameModule moduleEntryInfo)
|
||||||
{
|
{
|
||||||
return WriteProcessMemory((HANDLE)process.Handle, (void*)baseAddress, ref value, out _);
|
bool readOk = UnsafeReadModulesMemory(gameProcess, moduleEntryInfo, out VirtualMemory localMemory);
|
||||||
|
Verify.Operation(readOk, SH.ServiceGameUnlockerReadModuleMemoryCopyVirtualMemoryFailed);
|
||||||
|
|
||||||
|
using (localMemory)
|
||||||
|
{
|
||||||
|
int offset = IndexOfPattern(localMemory.AsSpan()[(int)moduleEntryInfo.UnityPlayer.Size..]);
|
||||||
|
Must.Range(offset >= 0, SH.ServiceGameUnlockerInterestedPatternNotFound);
|
||||||
|
|
||||||
|
byte* pLocalMemory = (byte*)localMemory.Pointer;
|
||||||
|
ref readonly Module unityPlayer = ref moduleEntryInfo.UnityPlayer;
|
||||||
|
ref readonly Module userAssembly = ref moduleEntryInfo.UserAssembly;
|
||||||
|
|
||||||
|
nuint localMemoryUnityPlayerAddress = (nuint)pLocalMemory;
|
||||||
|
nuint localMemoryUserAssemblyAddress = localMemoryUnityPlayerAddress + unityPlayer.Size;
|
||||||
|
|
||||||
|
nuint rip = localMemoryUserAssemblyAddress + (uint)offset;
|
||||||
|
rip += 5U;
|
||||||
|
rip += (nuint)(*(int*)(rip + 2U) + 6);
|
||||||
|
|
||||||
|
nuint address = userAssembly.Address + (rip - localMemoryUserAssemblyAddress);
|
||||||
|
|
||||||
|
nuint ptr = 0;
|
||||||
|
SpinWait.SpinUntil(() => UnsafeReadProcessMemory(gameProcess, address, out ptr) && ptr != 0);
|
||||||
|
|
||||||
|
rip = ptr - unityPlayer.Address + localMemoryUnityPlayerAddress;
|
||||||
|
|
||||||
|
// CALL or JMP
|
||||||
|
while (*(byte*)rip == 0xE8 || *(byte*)rip == 0xE9)
|
||||||
|
{
|
||||||
|
rip += (nuint)(*(int*)(rip + 1) + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
nuint localMemoryActualAddress = rip + *(uint*)(rip + 2) + 6;
|
||||||
|
nuint actualOffset = localMemoryActualAddress - localMemoryUnityPlayerAddress;
|
||||||
|
status.FpsAddress = unityPlayer.Address + actualOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly struct GameModule
|
||||||
|
{
|
||||||
|
public readonly bool HasValue = false;
|
||||||
|
public readonly Module UnityPlayer;
|
||||||
|
public readonly Module UserAssembly;
|
||||||
|
|
||||||
|
public GameModule(in Module unityPlayer, in Module userAssembly)
|
||||||
|
{
|
||||||
|
HasValue = true;
|
||||||
|
UnityPlayer = unityPlayer;
|
||||||
|
UserAssembly = userAssembly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly struct Module
|
||||||
|
{
|
||||||
|
public readonly bool HasValue = false;
|
||||||
|
public readonly nuint Address;
|
||||||
|
public readonly uint Size;
|
||||||
|
|
||||||
|
public Module(nuint address, uint size)
|
||||||
|
{
|
||||||
|
HasValue = true;
|
||||||
|
Address = address;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 解锁状态
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class GameFpsUnlockerContext
|
|
||||||
{
|
|
||||||
public string Description { get; set; } = default!;
|
|
||||||
|
|
||||||
public FindModuleResult FindModuleResult { get; set; }
|
|
||||||
|
|
||||||
public bool IsUnlockerValid { get; set; } = true;
|
|
||||||
|
|
||||||
public nuint FpsAddress { get; set; }
|
|
||||||
|
|
||||||
public UnlockTimingOptions TimingOptions { get; set; }
|
|
||||||
|
|
||||||
public Process GameProcess { get; set; } = default!;
|
|
||||||
|
|
||||||
public IProgress<GameFpsUnlockerContext> Progress { get; set; } = default!;
|
|
||||||
|
|
||||||
public void Report()
|
|
||||||
{
|
|
||||||
Progress.Report(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Core.Diagnostics;
|
|
||||||
using Snap.Hutao.Win32.Foundation;
|
|
||||||
using Snap.Hutao.Win32.Memory;
|
|
||||||
using Snap.Hutao.Win32.System.ProcessStatus;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using static Snap.Hutao.Win32.Kernel32;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
|
||||||
|
|
||||||
internal static class GameProcessModule
|
|
||||||
{
|
|
||||||
public static async ValueTask<ValueResult<FindModuleResult, RequiredGameModule>> FindModuleAsync(GameFpsUnlockerContext state)
|
|
||||||
{
|
|
||||||
ValueStopwatch watch = ValueStopwatch.StartNew();
|
|
||||||
using (PeriodicTimer timer = new(state.TimingOptions.FindModuleDelay))
|
|
||||||
{
|
|
||||||
while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
FindModuleResult result = UnsafeGetGameModuleInfo((HANDLE)state.GameProcess.Handle, out RequiredGameModule gameModule);
|
|
||||||
if (result == FindModuleResult.Ok)
|
|
||||||
{
|
|
||||||
return new(FindModuleResult.Ok, gameModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == FindModuleResult.NoModuleFound)
|
|
||||||
{
|
|
||||||
return new(FindModuleResult.NoModuleFound, default);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (watch.GetElapsedTime() > state.TimingOptions.FindModuleLimit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(FindModuleResult.TimeLimitExeeded, default);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FindModuleResult UnsafeGetGameModuleInfo(in HANDLE hProcess, out RequiredGameModule info)
|
|
||||||
{
|
|
||||||
FindModuleResult unityPlayerResult = UnsafeFindModule(hProcess, "UnityPlayer.dll", out Module unityPlayer);
|
|
||||||
FindModuleResult userAssemblyResult = UnsafeFindModule(hProcess, "UserAssembly.dll", out Module userAssembly);
|
|
||||||
|
|
||||||
if (unityPlayerResult is FindModuleResult.Ok && userAssemblyResult is FindModuleResult.Ok)
|
|
||||||
{
|
|
||||||
info = new(unityPlayer, userAssembly);
|
|
||||||
return FindModuleResult.Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unityPlayerResult is FindModuleResult.NoModuleFound && userAssemblyResult is FindModuleResult.NoModuleFound)
|
|
||||||
{
|
|
||||||
info = default;
|
|
||||||
return FindModuleResult.NoModuleFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = default;
|
|
||||||
return FindModuleResult.ModuleNotLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe FindModuleResult UnsafeFindModule(in HANDLE hProcess, in ReadOnlySpan<char> moduleName, out Module module)
|
|
||||||
{
|
|
||||||
HMODULE[] buffer = new HMODULE[128];
|
|
||||||
if (!K32EnumProcessModules(hProcess, buffer, out uint actualSize))
|
|
||||||
{
|
|
||||||
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actualSize == 0)
|
|
||||||
{
|
|
||||||
module = default!;
|
|
||||||
return FindModuleResult.NoModuleFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ref readonly HMODULE hModule in buffer.AsSpan()[..(int)(actualSize / sizeof(HMODULE))])
|
|
||||||
{
|
|
||||||
char[] baseName = new char[256];
|
|
||||||
|
|
||||||
if (K32GetModuleBaseNameW(hProcess, hModule, baseName) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (char* lpBaseName = baseName)
|
|
||||||
{
|
|
||||||
if (!moduleName.SequenceEqual(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(lpBaseName)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!K32GetModuleInformation(hProcess, hModule, out MODULEINFO moduleInfo))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
module = new((nuint)moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage);
|
|
||||||
return FindModuleResult.Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
module = default;
|
|
||||||
return FindModuleResult.ModuleNotLoaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,12 @@ namespace Snap.Hutao.Service.Game.Unlocker;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal interface IGameFpsUnlocker
|
internal interface IGameFpsUnlocker
|
||||||
{
|
{
|
||||||
ValueTask PostUnlockAsync(CancellationToken token = default);
|
/// <summary>
|
||||||
|
/// 异步的解锁帧数限制
|
||||||
ValueTask<bool> UnlockAsync(CancellationToken token = default);
|
/// </summary>
|
||||||
|
/// <param name="options">选项</param>
|
||||||
|
/// <param name="progress">进度</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>解锁的结果</returns>
|
||||||
|
ValueTask UnlockAsync(UnlockTimingOptions options, IProgress<UnlockerStatus> progress, CancellationToken token = default);
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
|
||||||
|
|
||||||
internal readonly struct Module
|
|
||||||
{
|
|
||||||
public readonly bool HasValue = false;
|
|
||||||
public readonly nuint Address;
|
|
||||||
public readonly uint Size;
|
|
||||||
|
|
||||||
public Module(nuint address, uint size)
|
|
||||||
{
|
|
||||||
HasValue = true;
|
|
||||||
Address = address;
|
|
||||||
Size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Unlocker;
|
|
||||||
|
|
||||||
internal readonly struct RequiredGameModule
|
|
||||||
{
|
|
||||||
public readonly bool HasValue = false;
|
|
||||||
public readonly Module UnityPlayer;
|
|
||||||
public readonly Module UserAssembly;
|
|
||||||
|
|
||||||
public RequiredGameModule(in Module unityPlayer, in Module userAssembly)
|
|
||||||
{
|
|
||||||
HasValue = true;
|
|
||||||
UnityPlayer = unityPlayer;
|
|
||||||
UserAssembly = userAssembly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Game.Unlocker;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解锁状态
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class UnlockerStatus
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态描述
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找模块状态
|
||||||
|
/// </summary>
|
||||||
|
public FindModuleResult FindModuleState { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前解锁器是否有效
|
||||||
|
/// </summary>
|
||||||
|
public bool IsUnlockerValid { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FPS 字节地址
|
||||||
|
/// </summary>
|
||||||
|
public nuint FpsAddress { get; set; }
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ namespace Snap.Hutao.Service.Hutao;
|
|||||||
[Injection(InjectAs.Scoped, typeof(IHutaoSpiralAbyssService))]
|
[Injection(InjectAs.Scoped, typeof(IHutaoSpiralAbyssService))]
|
||||||
internal sealed partial class HutaoSpiralAbyssService : IHutaoSpiralAbyssService
|
internal sealed partial class HutaoSpiralAbyssService : IHutaoSpiralAbyssService
|
||||||
{
|
{
|
||||||
private readonly TimeSpan cacheExpireTime = TimeSpan.FromHours(1);
|
private readonly TimeSpan cacheExpireTime = TimeSpan.FromHours(4);
|
||||||
|
|
||||||
private readonly IObjectCacheDbService objectCacheDbService;
|
private readonly IObjectCacheDbService objectCacheDbService;
|
||||||
private readonly HutaoSpiralAbyssClient homaClient;
|
private readonly HutaoSpiralAbyssClient homaClient;
|
||||||
|
|||||||
@@ -302,8 +302,8 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -311,14 +311,14 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.2.0" />
|
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.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>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240311000" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240227000" />
|
||||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||||
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
||||||
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">
|
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
d:DataContext="{d:DesignInstance shva:AchievementViewModelSlim}"
|
d:DataContext="{d:DesignInstance shva:AchievementViewModelSlim}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
Command="{Binding NavigateCommand}"
|
Command="{Binding NavigateCommand}"
|
||||||
Style="{ThemeResource DefaultButtonStyle}"
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
d:DataContext="{d:DesignInstance shvd:DailyNoteViewModelSlim}"
|
d:DataContext="{d:DesignInstance shvd:DailyNoteViewModelSlim}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
Command="{Binding NavigateCommand}"
|
Command="{Binding NavigateCommand}"
|
||||||
Style="{ThemeResource DefaultButtonStyle}"
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
d:DataContext="{d:DesignInstance shvg:GachaLogViewModelSlim}"
|
d:DataContext="{d:DesignInstance shvg:GachaLogViewModelSlim}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
Command="{Binding NavigateCommand}"
|
Command="{Binding NavigateCommand}"
|
||||||
Style="{ThemeResource DefaultButtonStyle}"
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
@@ -70,7 +69,7 @@
|
|||||||
Maximum="{Binding GuaranteeOrangeThreshold}"
|
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||||
ProgressForeground="{StaticResource OrangeColorBrush}"
|
ProgressForeground="{StaticResource OrangeColorBrush}"
|
||||||
TextForeground="{StaticResource OrangeColorBrush}"
|
TextForeground="{StaticResource OrangeColorBrush}"
|
||||||
Value="{Binding LastOrangePull, Mode=OneWay}"/>
|
Value="{Binding LastOrangePull}"/>
|
||||||
<shvcp:CardProgressBar
|
<shvcp:CardProgressBar
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Description="{Binding LastPurplePull}"
|
Description="{Binding LastPurplePull}"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
d:DataContext="{d:DesignInstance shvg:LaunchGameViewModelSlim}"
|
d:DataContext="{d:DesignInstance shvg:LaunchGameViewModelSlim}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
Command="{Binding LaunchCommand}"
|
Command="{Binding LaunchCommand}"
|
||||||
Style="{ThemeResource DefaultButtonStyle}"
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|||||||
@@ -1,49 +1,39 @@
|
|||||||
<ResourceDictionary
|
<Grid
|
||||||
|
x:Class="Snap.Hutao.View.Card.Primitive.CardProgressBar"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:shvcp="using:Snap.Hutao.View.Card.Primitive">
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
MinHeight="40"
|
||||||
|
Style="{ThemeResource GridCardStyle}"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Style BasedOn="{StaticResource DefaultCardProgressBarStyle}" TargetType="shvcp:CardProgressBar"/>
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
<Style x:Key="DefaultCardProgressBarStyle" TargetType="shvcp:CardProgressBar">
|
<ColumnDefinition/>
|
||||||
<Setter Property="TextForeground" Value="{ThemeResource TextFillColorPrimaryBrush}"/>
|
</Grid.ColumnDefinitions>
|
||||||
<Setter Property="MinHeight" Value="40"/>
|
<ProgressBar
|
||||||
<Setter Property="Template">
|
Grid.ColumnSpan="2"
|
||||||
<Setter.Value>
|
MinHeight="{x:Bind MinHeight, Mode=OneWay}"
|
||||||
<ControlTemplate>
|
Background="Transparent"
|
||||||
<Grid MinHeight="{TemplateBinding MinHeight}" Style="{ThemeResource GridCardStyle}">
|
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||||
<Grid.ColumnDefinitions>
|
Foreground="{x:Bind ProgressForeground, Mode=OneWay}"
|
||||||
<ColumnDefinition Width="auto"/>
|
Maximum="{x:Bind Maximum, Mode=OneWay}"
|
||||||
<ColumnDefinition/>
|
Opacity="{StaticResource LargeBackgroundProgressBarOpacity}"
|
||||||
</Grid.ColumnDefinitions>
|
Value="{x:Bind Value, Mode=OneWay}"/>
|
||||||
<ProgressBar
|
<TextBlock
|
||||||
Grid.ColumnSpan="2"
|
Grid.Column="0"
|
||||||
MinHeight="{TemplateBinding MinHeight}"
|
Margin="6,0"
|
||||||
Background="Transparent"
|
HorizontalAlignment="Center"
|
||||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
VerticalAlignment="Center"
|
||||||
Foreground="{Binding ProgressForeground, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
|
Foreground="{x:Bind TextForeground, Mode=OneWay}"
|
||||||
Maximum="{Binding Maximum, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
Opacity="{StaticResource LargeBackgroundProgressBarOpacity}"
|
Text="{x:Bind Header, Mode=OneWay}"/>
|
||||||
Value="{Binding Value, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
|
<TextBlock
|
||||||
<TextBlock
|
Grid.Column="1"
|
||||||
Grid.Column="0"
|
HorizontalAlignment="Center"
|
||||||
Margin="6,0"
|
VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
Foreground="{x:Bind TextForeground, Mode=OneWay}"
|
||||||
VerticalAlignment="Center"
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
Foreground="{Binding TextForeground, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
|
Text="{x:Bind Description, Mode=OneWay}"/>
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
</Grid>
|
||||||
Text="{Binding Header, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Foreground="{Binding TextForeground, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="{Binding Description, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
|
||||||
|
|||||||
@@ -13,9 +13,12 @@ namespace Snap.Hutao.View.Card.Primitive;
|
|||||||
[DependencyProperty("Value", typeof(double))]
|
[DependencyProperty("Value", typeof(double))]
|
||||||
[DependencyProperty("Header", typeof(string))]
|
[DependencyProperty("Header", typeof(string))]
|
||||||
[DependencyProperty("Description", typeof(string))]
|
[DependencyProperty("Description", typeof(string))]
|
||||||
internal sealed partial class CardProgressBar : ContentControl
|
internal sealed partial class CardProgressBar : Grid
|
||||||
{
|
{
|
||||||
public CardProgressBar()
|
public CardProgressBar()
|
||||||
{
|
{
|
||||||
|
IAppResourceProvider appResourceProvider = Ioc.Default.GetRequiredService<IAppResourceProvider>();
|
||||||
|
TextForeground = appResourceProvider.GetResource<Brush>("TextFillColorPrimaryBrush");
|
||||||
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,49 +52,41 @@
|
|||||||
Margin="0,16,0,8"
|
Margin="0,16,0,8"
|
||||||
Foreground="{ThemeResource UpPullColorBrush}"
|
Foreground="{ThemeResource UpPullColorBrush}"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardUpText}"
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardUpText}"/>
|
||||||
Visibility="{Binding UpItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
ItemTemplate="{StaticResource GridTemplate}"
|
ItemTemplate="{StaticResource GridTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
||||||
ItemsSource="{Binding UpItems}"
|
ItemsSource="{Binding UpItems}"/>
|
||||||
Visibility="{Binding UpItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,16,0,8"
|
Margin="0,16,0,8"
|
||||||
Foreground="{ThemeResource OrangeColorBrush}"
|
Foreground="{ThemeResource OrangeColorBrush}"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||||
Visibility="{Binding OrangeItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
ItemTemplate="{StaticResource GridTemplate}"
|
ItemTemplate="{StaticResource GridTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
||||||
ItemsSource="{Binding OrangeItems}"
|
ItemsSource="{Binding OrangeItems}"/>
|
||||||
Visibility="{Binding OrangeItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,16,0,8"
|
Margin="0,16,0,8"
|
||||||
Foreground="{ThemeResource PurpleColorBrush}"
|
Foreground="{ThemeResource PurpleColorBrush}"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||||
Visibility="{Binding PurpleItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
ItemTemplate="{StaticResource GridTemplate}"
|
ItemTemplate="{StaticResource GridTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
||||||
ItemsSource="{Binding PurpleItems}"
|
ItemsSource="{Binding PurpleItems}"/>
|
||||||
Visibility="{Binding PurpleItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,16,0,8"
|
Margin="0,16,0,8"
|
||||||
Foreground="{ThemeResource BlueColorBrush}"
|
Foreground="{ThemeResource BlueColorBrush}"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardBlueText}"
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardBlueText}"/>
|
||||||
Visibility="{Binding BlueItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
ItemTemplate="{StaticResource GridTemplate}"
|
ItemTemplate="{StaticResource GridTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
ItemsPanel="{StaticResource WrapPanelSpacing4Template}"
|
||||||
ItemsSource="{Binding BlueItems}"
|
ItemsSource="{Binding BlueItems}"/>
|
||||||
Visibility="{Binding BlueItems.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -21,12 +21,6 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<shvconv:BoolToGridLengthConverter x:Key="BoolToGridLengthConverter"/>
|
|
||||||
<shvconv:BoolToGridLengthConverter
|
|
||||||
x:Key="BoolToGridLengthSpacingConverter"
|
|
||||||
FalseValue="0"
|
|
||||||
TrueValue="4"/>
|
|
||||||
|
|
||||||
<shvconv:Int32ToGradientColorConverter x:Key="Int32ToGradientColorConverter" MaximumValue="{Binding GuaranteeOrangeThreshold}"/>
|
<shvconv:Int32ToGradientColorConverter x:Key="Int32ToGradientColorConverter" MaximumValue="{Binding GuaranteeOrangeThreshold}"/>
|
||||||
|
|
||||||
<DataTemplate x:Key="OrangeListTemplate" d:DataType="shvg:SummaryItem">
|
<DataTemplate x:Key="OrangeListTemplate" d:DataType="shvg:SummaryItem">
|
||||||
@@ -232,12 +226,10 @@
|
|||||||
Padding="0,12"
|
Padding="0,12"
|
||||||
Value="{x:Bind StatisticsSegmented.SelectedIndex, Mode=OneWay}">
|
Value="{x:Bind StatisticsSegmented.SelectedIndex, Mode=OneWay}">
|
||||||
<cwcont:Case Value="{shcm:Int32 Value=0}">
|
<cwcont:Case Value="{shcm:Int32 Value=0}">
|
||||||
<Grid>
|
<Grid ColumnSpacing="2">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition Width="{x:Bind ShowUpPull, Converter={StaticResource BoolToGridLengthSpacingConverter}}"/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition Width="{x:Bind ShowUpPull, Converter={StaticResource BoolToGridLengthConverter}}"/>
|
|
||||||
<ColumnDefinition Width="4"/>
|
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Border Grid.Column="0" Style="{ThemeResource BorderCardStyle}">
|
<Border Grid.Column="0" Style="{ThemeResource BorderCardStyle}">
|
||||||
@@ -251,7 +243,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Grid.Column="2" Style="{ThemeResource BorderCardStyle}">
|
<Border Grid.Column="1" Style="{ThemeResource BorderCardStyle}">
|
||||||
<Viewbox Margin="8,0" StretchDirection="DownOnly">
|
<Viewbox Margin="8,0" StretchDirection="DownOnly">
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
@@ -274,7 +266,7 @@
|
|||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Grid Grid.Column="4" RowSpacing="4">
|
<Grid Grid.Column="2" RowSpacing="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
@@ -306,7 +298,7 @@
|
|||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid ColumnSpacing="4">
|
<Grid ColumnSpacing="2">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
@@ -368,7 +360,7 @@
|
|||||||
|
|
||||||
</cwcont:Case>
|
</cwcont:Case>
|
||||||
<cwcont:Case Value="{shcm:Int32 Value=2}">
|
<cwcont:Case Value="{shcm:Int32 Value=2}">
|
||||||
<Grid RowSpacing="4">
|
<Grid RowSpacing="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using CommunityToolkit.WinUI.Converters;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Converter;
|
|
||||||
|
|
||||||
internal sealed class BoolToGridLengthConverter : BoolToObjectConverter
|
|
||||||
{
|
|
||||||
public BoolToGridLengthConverter()
|
|
||||||
{
|
|
||||||
TrueValue = new GridLength(1D, GridUnitType.Star);
|
|
||||||
FalseValue = new GridLength(0D);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
LocalSettingKeySuffixForCurrent="AchievementPage.AchievementGoals"/>
|
LocalSettingKeySuffixForCurrent="AchievementPage.AchievementGoals"/>
|
||||||
<Viewbox
|
<Viewbox
|
||||||
Height="32"
|
Height="32"
|
||||||
MaxWidth="190"
|
MaxWidth="192"
|
||||||
Margin="8,0,0,0"
|
Margin="8,0,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Stretch="Uniform"
|
Stretch="Uniform"
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
cw:VisualExtensions.NormalizedCenterPoint="0.5">
|
cw:VisualExtensions.NormalizedCenterPoint="0.5">
|
||||||
<cww:ConstrainedBox AspectRatio="1080:390" CornerRadius="{ThemeResource ControlCornerRadiusTop}">
|
<cww:ConstrainedBox AspectRatio="1080:390" CornerRadius="{ThemeResource ControlCornerRadiusTop}">
|
||||||
<shci:CachedImage
|
<shci:CachedImage
|
||||||
Margin="-1"
|
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
PlaceholderMargin="16"
|
PlaceholderMargin="16"
|
||||||
PlaceholderSource="{StaticResource UI_EmotionIcon271}"
|
PlaceholderSource="{StaticResource UI_EmotionIcon271}"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:clw="using:CommunityToolkit.Labs.WinUI"
|
xmlns:clw="using:CommunityToolkit.Labs.WinUI"
|
||||||
xmlns:cw="using:CommunityToolkit.WinUI"
|
|
||||||
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls"
|
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:cwconv="using:CommunityToolkit.WinUI.Converters"
|
xmlns:cwconv="using:CommunityToolkit.WinUI.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -51,248 +50,240 @@
|
|||||||
<SplitView.Pane>
|
<SplitView.Pane>
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<StackPanel Margin="16" Spacing="3">
|
<StackPanel Margin="16" Spacing="3">
|
||||||
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
<cwcont:SettingsExpander
|
||||||
<cwcont:SettingsExpander
|
Description="{Binding RuntimeOptions.Version}"
|
||||||
Description="{Binding RuntimeOptions.Version}"
|
Header="{shcm:ResourceString Name=AppName}"
|
||||||
Header="{shcm:ResourceString Name=AppName}"
|
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
IsExpanded="True">
|
||||||
IsExpanded="True">
|
<cwcont:SettingsExpander.Items>
|
||||||
<cwcont:SettingsExpander.Items>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
|
||||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
|
Command="{Binding CopyDeviceIdCommand}"
|
||||||
Command="{Binding CopyDeviceIdCommand}"
|
Description="{Binding RuntimeOptions.DeviceId}"
|
||||||
Description="{Binding RuntimeOptions.DeviceId}"
|
Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard Description="{Binding IPInformation}" Header="{shcm:ResourceString Name=ViewPageSettingDeviceIpHeader}"/>
|
||||||
<cwcont:SettingsCard Description="{Binding IPInformation}" Header="{shcm:ResourceString Name=ViewPageSettingDeviceIpHeader}"/>
|
<cwcont:SettingsCard Description="{Binding DynamicHttpProxy.CurrentProxyUri}" Header="{shcm:ResourceString Name=ViewPageFeedbackCurrentProxyHeader}"/>
|
||||||
<cwcont:SettingsCard Description="{Binding DynamicHttpProxy.CurrentProxyUri}" Header="{shcm:ResourceString Name=ViewPageFeedbackCurrentProxyHeader}"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Command="{Binding EnableLoopbackCommand}"
|
||||||
Command="{Binding EnableLoopbackCommand}"
|
Header="{shcm:ResourceString Name=ViewPageFeedbackEnableLoopbackHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageFeedbackEnableLoopbackHeader}"
|
IsClickEnabled="True"
|
||||||
IsClickEnabled="True"
|
IsEnabled="{Binding LoopbackManager.IsLoopbackEnabled, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||||
IsEnabled="{Binding LoopbackManager.IsLoopbackEnabled, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
<cwcont:SettingsCard.Description>
|
||||||
<cwcont:SettingsCard.Description>
|
<UserControl Content="{Binding LoopbackManager.IsLoopbackEnabled, Converter={StaticResource BoolToLoopbackDescriptionControlConverter}, Mode=OneWay}"/>
|
||||||
<UserControl Content="{Binding LoopbackManager.IsLoopbackEnabled, Converter={StaticResource BoolToLoopbackDescriptionControlConverter}, Mode=OneWay}"/>
|
</cwcont:SettingsCard.Description>
|
||||||
</cwcont:SettingsCard.Description>
|
</cwcont:SettingsCard>
|
||||||
</cwcont:SettingsCard>
|
<cwcont:SettingsCard Description="{Binding RuntimeOptions.WebView2Version}" Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"/>
|
||||||
<cwcont:SettingsCard Description="{Binding RuntimeOptions.WebView2Version}" Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"/>
|
</cwcont:SettingsExpander.Items>
|
||||||
</cwcont:SettingsExpander.Items>
|
</cwcont:SettingsExpander>
|
||||||
</cwcont:SettingsExpander>
|
|
||||||
</Border>
|
|
||||||
</Border>
|
</Border>
|
||||||
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
<cwcont:SettingsExpander
|
||||||
<cwcont:SettingsExpander
|
Description="{shcm:ResourceString Name=ViewPageFeedbackEngageWithUsDescription}"
|
||||||
Description="{shcm:ResourceString Name=ViewPageFeedbackEngageWithUsDescription}"
|
Header="{shcm:ResourceString Name=ViewPageFeedbackCommonLinksHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageFeedbackCommonLinksHeader}"
|
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
IsExpanded="True">
|
||||||
IsExpanded="True">
|
<cwcont:SettingsExpander.Items>
|
||||||
<cwcont:SettingsExpander.Items>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://github.com/DGP-Studio/Snap.Hutao/issues/new/choose"
|
||||||
CommandParameter="https://github.com/DGP-Studio/Snap.Hutao/issues/new/choose"
|
Description="{shcm:ResourceString Name=ViewPageFeedbackGithubIssuesDescription}"
|
||||||
Description="{shcm:ResourceString Name=ViewPageFeedbackGithubIssuesDescription}"
|
Header="GitHub Issues"
|
||||||
Header="GitHub Issues"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://github.com/orgs/DGP-Studio/projects/2"
|
||||||
CommandParameter="https://github.com/orgs/DGP-Studio/projects/2"
|
Description="{shcm:ResourceString Name=ViewPageFeedbackRoadmapDescription}"
|
||||||
Description="{shcm:ResourceString Name=ViewPageFeedbackRoadmapDescription}"
|
Header="GitHub Projects"
|
||||||
Header="GitHub Projects"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://status.hut.ao"
|
||||||
CommandParameter="https://status.hut.ao"
|
Description="{shcm:ResourceString Name=ViewPageFeedbackServerStatusDescription}"
|
||||||
Description="{shcm:ResourceString Name=ViewPageFeedbackServerStatusDescription}"
|
Header="{shcm:ResourceString Name=ViewPageFeedbackServerStatusHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageFeedbackServerStatusHeader}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
</cwcont:SettingsExpander.Items>
|
||||||
</cwcont:SettingsExpander.Items>
|
</cwcont:SettingsExpander>
|
||||||
</cwcont:SettingsExpander>
|
|
||||||
</Border>
|
|
||||||
</Border>
|
</Border>
|
||||||
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
<cwcont:SettingsExpander
|
||||||
<cwcont:SettingsExpander
|
Header="{shcm:ResourceString Name=ViewPageFeedbackFeatureGuideHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewPageFeedbackFeatureGuideHeader}"
|
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
IsExpanded="True">
|
||||||
IsExpanded="True">
|
<cwcont:SettingsExpander.Items>
|
||||||
<cwcont:SettingsExpander.Items>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/dashboard.html"
|
||||||
CommandParameter="https://hut.ao/features/dashboard.html"
|
Header="{shcm:ResourceString Name=ViewAnnouncementHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewAnnouncementHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Announcement.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Announcement.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/game-launcher.html"
|
||||||
CommandParameter="https://hut.ao/features/game-launcher.html"
|
Header="{shcm:ResourceString Name=ViewLaunchGameHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewLaunchGameHeader}"
|
IsClickEnabled="True">
|
||||||
IsClickEnabled="True">
|
<cwcont:SettingsCard.HeaderIcon>
|
||||||
<cwcont:SettingsCard.HeaderIcon>
|
<!-- This icon is not a square -->
|
||||||
<!-- This icon is not a square -->
|
<BitmapIcon
|
||||||
<BitmapIcon
|
Width="24"
|
||||||
Width="24"
|
Height="24"
|
||||||
Height="24"
|
ShowAsMonochrome="False"
|
||||||
ShowAsMonochrome="False"
|
UriSource="ms-appx:///Resource/Navigation/LaunchGame.png"/>
|
||||||
UriSource="ms-appx:///Resource/Navigation/LaunchGame.png"/>
|
</cwcont:SettingsCard.HeaderIcon>
|
||||||
</cwcont:SettingsCard.HeaderIcon>
|
</cwcont:SettingsCard>
|
||||||
</cwcont:SettingsCard>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/wish-export.html"
|
||||||
CommandParameter="https://hut.ao/features/wish-export.html"
|
Header="{shcm:ResourceString Name=ViewGachaLogHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewGachaLogHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/GachaLog.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/GachaLog.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/achievements.html"
|
||||||
CommandParameter="https://hut.ao/features/achievements.html"
|
Header="{shcm:ResourceString Name=ViewAchievementHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewAchievementHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Achievement.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Achievement.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/real-time-notes.html"
|
||||||
CommandParameter="https://hut.ao/features/real-time-notes.html"
|
Header="{shcm:ResourceString Name=ViewDailyNoteHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewDailyNoteHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/DailyNote.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/DailyNote.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/character-data.html"
|
||||||
CommandParameter="https://hut.ao/features/character-data.html"
|
Header="{shcm:ResourceString Name=ViewAvatarPropertyHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewAvatarPropertyHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/AvatarProperty.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/AvatarProperty.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/hutao-API.html"
|
||||||
CommandParameter="https://hut.ao/features/hutao-API.html"
|
Header="{shcm:ResourceString Name=ViewSpiralAbyssHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewSpiralAbyssHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/SpiralAbyss.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/SpiralAbyss.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/develop-plan.html"
|
||||||
CommandParameter="https://hut.ao/features/develop-plan.html"
|
Header="{shcm:ResourceString Name=ViewCultivationHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewCultivationHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Cultivation.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Cultivation.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/character-wiki.html"
|
||||||
CommandParameter="https://hut.ao/features/character-wiki.html"
|
Header="{shcm:ResourceString Name=ViewWikiAvatarHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewWikiAvatarHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiAvatar.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiAvatar.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/weapon-wiki.html"
|
||||||
CommandParameter="https://hut.ao/features/weapon-wiki.html"
|
Header="{shcm:ResourceString Name=ViewWikiWeaponHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewWikiWeaponHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiWeapon.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiWeapon.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/monster-wiki.html"
|
||||||
CommandParameter="https://hut.ao/features/monster-wiki.html"
|
Header="{shcm:ResourceString Name=ViewWikiMonsterHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewWikiMonsterHeader}"
|
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiMonster.png}"
|
||||||
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiMonster.png}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
<cwcont:SettingsCard
|
||||||
<cwcont:SettingsCard
|
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
Command="{Binding NavigateToUriCommand}"
|
||||||
Command="{Binding NavigateToUriCommand}"
|
CommandParameter="https://hut.ao/features/hutao-settings.html"
|
||||||
CommandParameter="https://hut.ao/features/hutao-settings.html"
|
Header="{shcm:ResourceString Name=ViewSettingHeader}"
|
||||||
Header="{shcm:ResourceString Name=ViewSettingHeader}"
|
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
IsClickEnabled="True"/>
|
||||||
IsClickEnabled="True"/>
|
</cwcont:SettingsExpander.Items>
|
||||||
</cwcont:SettingsExpander.Items>
|
</cwcont:SettingsExpander>
|
||||||
</cwcont:SettingsExpander>
|
|
||||||
</Border>
|
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</SplitView.Pane>
|
</SplitView.Pane>
|
||||||
<Border Margin="16,16,0,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Grid Margin="16,16,0,16" Style="{ThemeResource AcrylicGridCardStyle}">
|
||||||
<Grid Style="{ThemeResource AcrylicGridCardStyle}">
|
<Grid
|
||||||
<Grid
|
Padding="16"
|
||||||
Padding="16"
|
RowSpacing="8"
|
||||||
RowSpacing="8"
|
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||||
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
<Grid.RowDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition/>
|
||||||
<RowDefinition/>
|
</Grid.RowDefinitions>
|
||||||
</Grid.RowDefinitions>
|
<AutoSuggestBox
|
||||||
<AutoSuggestBox
|
Grid.Row="0"
|
||||||
Grid.Row="0"
|
Height="36"
|
||||||
Height="36"
|
Margin="0,0,0,8"
|
||||||
Margin="0,0,0,8"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
VerticalContentAlignment="Center"
|
||||||
VerticalContentAlignment="Center"
|
PlaceholderText="{shcm:ResourceString Name=ViewPageFeedbackAutoSuggestBoxPlaceholder}"
|
||||||
PlaceholderText="{shcm:ResourceString Name=ViewPageFeedbackAutoSuggestBoxPlaceholder}"
|
QueryIcon="{shcm:FontIcon Glyph=}"
|
||||||
QueryIcon="{shcm:FontIcon Glyph=}"
|
Style="{StaticResource DefaultAutoSuggestBoxStyle}"
|
||||||
Style="{StaticResource DefaultAutoSuggestBoxStyle}"
|
Text="{Binding SearchText, Mode=TwoWay}">
|
||||||
Text="{Binding SearchText, Mode=TwoWay}">
|
<mxi:Interaction.Behaviors>
|
||||||
<mxi:Interaction.Behaviors>
|
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
|
||||||
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
|
<mxic:InvokeCommandAction Command="{Binding SearchDocumentCommand}" CommandParameter="{Binding SearchText}"/>
|
||||||
<mxic:InvokeCommandAction Command="{Binding SearchDocumentCommand}" CommandParameter="{Binding SearchText}"/>
|
</mxic:EventTriggerBehavior>
|
||||||
</mxic:EventTriggerBehavior>
|
</mxi:Interaction.Behaviors>
|
||||||
</mxi:Interaction.Behaviors>
|
</AutoSuggestBox>
|
||||||
</AutoSuggestBox>
|
<StackPanel
|
||||||
<StackPanel
|
Grid.Row="1"
|
||||||
Grid.Row="1"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
Visibility="{Binding SearchResults.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
|
||||||
Visibility="{Binding SearchResults.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
|
<shci:CachedImage
|
||||||
<shci:CachedImage
|
Height="120"
|
||||||
Height="120"
|
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
|
||||||
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
|
EnableLazyLoading="False"
|
||||||
EnableLazyLoading="False"
|
Source="{StaticResource UI_EmotionIcon52}"/>
|
||||||
Source="{StaticResource UI_EmotionIcon52}"/>
|
<TextBlock
|
||||||
<TextBlock
|
Margin="0,5,0,21"
|
||||||
Margin="0,5,0,21"
|
HorizontalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
Text="{shcm:ResourceString Name=ViewPageFeedbackSearchResultPlaceholderTitle}"/>
|
||||||
Text="{shcm:ResourceString Name=ViewPageFeedbackSearchResultPlaceholderTitle}"/>
|
</StackPanel>
|
||||||
</StackPanel>
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
|
||||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
|
<ItemsControl
|
||||||
<ItemsControl
|
ItemContainerTransitions="{ThemeResource ListViewLikeThemeTransitions}"
|
||||||
ItemContainerTransitions="{ThemeResource ListViewLikeThemeTransitions}"
|
ItemsPanel="{ThemeResource StackPanelSpacing8Template}"
|
||||||
ItemsPanel="{ThemeResource StackPanelSpacing8Template}"
|
ItemsSource="{Binding SearchResults}">
|
||||||
ItemsSource="{Binding SearchResults}">
|
<ItemsControl.ItemTemplate>
|
||||||
<ItemsControl.ItemTemplate>
|
<DataTemplate>
|
||||||
<DataTemplate>
|
<Border Style="{ThemeResource BorderCardStyle}">
|
||||||
<Border Style="{ThemeResource BorderCardStyle}">
|
<HyperlinkButton
|
||||||
<HyperlinkButton
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
NavigateUri="{Binding Url}">
|
||||||
NavigateUri="{Binding Url}">
|
<Grid>
|
||||||
<Grid>
|
<Grid.ColumnDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition Width="auto"/>
|
||||||
<ColumnDefinition Width="auto"/>
|
</Grid.ColumnDefinitions>
|
||||||
</Grid.ColumnDefinitions>
|
<BreadcrumbBar
|
||||||
<BreadcrumbBar
|
Grid.Column="0"
|
||||||
Grid.Column="0"
|
Margin="4,8,8,4"
|
||||||
Margin="4,8,8,4"
|
IsHitTestVisible="False"
|
||||||
IsHitTestVisible="False"
|
ItemsSource="{Binding Hierarchy.DisplayLevels}"/>
|
||||||
ItemsSource="{Binding Hierarchy.DisplayLevels}"/>
|
</Grid>
|
||||||
</Grid>
|
</HyperlinkButton>
|
||||||
</HyperlinkButton>
|
</Border>
|
||||||
</Border>
|
</DataTemplate>
|
||||||
</DataTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl>
|
||||||
</ItemsControl>
|
</ScrollViewer>
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<clw:Shimmer IsActive="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityRevertConverter}, Mode=OneWay}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
|
||||||
|
<clw:Shimmer IsActive="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityRevertConverter}, Mode=OneWay}"/>
|
||||||
|
</Grid>
|
||||||
</SplitView>
|
</SplitView>
|
||||||
</Grid>
|
</Grid>
|
||||||
</shc:ScopedPage>
|
</shc:ScopedPage>
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
|
||||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||||
xmlns:shvg="using:Snap.Hutao.ViewModel.GachaLog"
|
xmlns:shvg="using:Snap.Hutao.ViewModel.GachaLog"
|
||||||
d:DataContext="{d:DesignInstance shvg:GachaLogViewModel}"
|
d:DataContext="{d:DesignInstance shvg:GachaLogViewModel}"
|
||||||
@@ -143,8 +142,8 @@
|
|||||||
<Border Width="40" Style="{StaticResource BorderCardStyle}">
|
<Border Width="40" Style="{StaticResource BorderCardStyle}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<shvc:ItemIcon
|
<shvc:ItemIcon
|
||||||
Width="38"
|
Width="40"
|
||||||
Height="38"
|
Height="40"
|
||||||
Icon="{Binding Icon}"
|
Icon="{Binding Icon}"
|
||||||
Quality="{Binding Quality}"/>
|
Quality="{Binding Quality}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -183,19 +182,17 @@
|
|||||||
Text="{Binding TotalCountFormatted}"/>
|
Text="{Binding TotalCountFormatted}"/>
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
MaxWidth="124"
|
|
||||||
Margin="0,6,0,0"
|
Margin="0,6,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
ItemTemplate="{StaticResource HistoryWishItemTemplate}"
|
ItemTemplate="{StaticResource HistoryWishItemTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing2Template}"
|
ItemsPanel="{StaticResource HorizontalStackPanelSpacing2Template}"
|
||||||
ItemsSource="{Binding OrangeUpList}"/>
|
ItemsSource="{Binding OrangeUpList}"/>
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
MaxWidth="252"
|
|
||||||
Margin="0,6,0,0"
|
Margin="0,6,0,0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
ItemTemplate="{StaticResource HistoryWishItemTemplate}"
|
ItemTemplate="{StaticResource HistoryWishItemTemplate}"
|
||||||
ItemsPanel="{StaticResource WrapPanelSpacing2Template}"
|
ItemsPanel="{StaticResource HorizontalStackPanelSpacing2Template}"
|
||||||
ItemsSource="{Binding PurpleUpList}"/>
|
ItemsSource="{Binding PurpleUpList}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -288,22 +285,26 @@
|
|||||||
</CommandBar>
|
</CommandBar>
|
||||||
</Pivot.RightHeader>
|
</Pivot.RightHeader>
|
||||||
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotOverview}">
|
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotOverview}">
|
||||||
<ScrollViewer
|
<Grid Margin="0,0,16,0">
|
||||||
Margin="16,0"
|
<Grid.ColumnDefinitions>
|
||||||
cw:ScrollViewerExtensions.HorizontalScrollBarMargin="0,0,-16,0"
|
<ColumnDefinition/>
|
||||||
HorizontalScrollBarVisibility="Auto"
|
<ColumnDefinition/>
|
||||||
HorizontalScrollMode="Enabled"
|
<ColumnDefinition/>
|
||||||
VerticalScrollMode="Disabled">
|
</Grid.ColumnDefinitions>
|
||||||
<shcp:HorizontalEqualPanel
|
<shvc:StatisticsCard
|
||||||
Margin="0,16"
|
Grid.Column="0"
|
||||||
MinItemWidth="302"
|
Margin="16,16,0,16"
|
||||||
Spacing="16">
|
DataContext="{Binding Statistics.AvatarWish}"/>
|
||||||
<shvc:StatisticsCard DataContext="{Binding Statistics.AvatarWish}"/>
|
<shvc:StatisticsCard
|
||||||
<shvc:StatisticsCard DataContext="{Binding Statistics.WeaponWish}"/>
|
Grid.Column="1"
|
||||||
<shvc:StatisticsCard DataContext="{Binding Statistics.StandardWish}" ShowUpPull="False"/>
|
Margin="16,16,0,16"
|
||||||
<shvc:StatisticsCard DataContext="{Binding Statistics.ChronicledWish}" ShowUpPull="False"/>
|
DataContext="{Binding Statistics.WeaponWish}"/>
|
||||||
</shcp:HorizontalEqualPanel>
|
<shvc:StatisticsCard
|
||||||
</ScrollViewer>
|
Grid.Column="2"
|
||||||
|
Margin="16,16,0,16"
|
||||||
|
DataContext="{Binding Statistics.StandardWish}"
|
||||||
|
ShowUpPull="False"/>
|
||||||
|
</Grid>
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotHistory}">
|
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotHistory}">
|
||||||
<Border Margin="16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<Border Margin="16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||||
@@ -311,7 +312,7 @@
|
|||||||
<SplitView
|
<SplitView
|
||||||
DisplayMode="Inline"
|
DisplayMode="Inline"
|
||||||
IsPaneOpen="True"
|
IsPaneOpen="True"
|
||||||
OpenPaneLength="408"
|
OpenPaneLength="323"
|
||||||
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
PaneBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
|
||||||
<SplitView.Pane>
|
<SplitView.Pane>
|
||||||
<ListView
|
<ListView
|
||||||
@@ -378,6 +379,7 @@
|
|||||||
</SplitView>
|
</SplitView>
|
||||||
</Border>
|
</Border>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotAvatar}">
|
<PivotItem Header="{shcm:ResourceString Name=ViewPageGahcaLogPivotAvatar}">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
@@ -479,14 +481,13 @@
|
|||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="0" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="0" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent}"/>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="1" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent2}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="1" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.AvatarEvent2}"/>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="2" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.WeaponEvent}"/>
|
<shvc:HutaoStatisticsCard Grid.Column="2" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.WeaponEvent}"/>
|
||||||
<shvc:HutaoStatisticsCard Grid.Column="3" DataContext="{Binding HutaoCloudStatisticsViewModel.Statistics.Chronicled}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
</Pivot>
|
</Pivot>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -348,7 +348,6 @@
|
|||||||
</mxic:EventTriggerBehavior>
|
</mxic:EventTriggerBehavior>
|
||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
</cwc:SettingsCard>
|
</cwc:SettingsCard>
|
||||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewPageSettingBackgroundImageLocalFolderCopyrightHeader}" Visibility="{Binding BackgroundImageOptions.Wallpaper, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
|
|
||||||
</cwc:SettingsExpander.Items>
|
</cwc:SettingsExpander.Items>
|
||||||
</cwc:SettingsExpander>
|
</cwc:SettingsExpander>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -74,28 +74,30 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="TokenTemplate">
|
<DataTemplate x:Key="TokenTemplate">
|
||||||
<Grid VerticalAlignment="Center">
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="22"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Ellipse
|
<Rectangle
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="12"
|
Width="4"
|
||||||
Height="12"
|
Height="22"
|
||||||
Margin="1,1,0,0"
|
Margin="0,0,8,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
RadiusX="2"
|
||||||
|
RadiusY="2"
|
||||||
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||||
<Ellipse.Fill>
|
<Rectangle.Fill>
|
||||||
<SolidColorBrush Color="{Binding Quality}"/>
|
<SolidColorBrush Color="{Binding Quality}"/>
|
||||||
</Ellipse.Fill>
|
</Rectangle.Fill>
|
||||||
</Ellipse>
|
</Rectangle>
|
||||||
<shci:MonoChrome
|
<shci:MonoChrome
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="22"
|
Width="22"
|
||||||
Height="22"
|
Height="22"
|
||||||
Margin="-3,2,7,0"
|
Margin="0,0,4,0"
|
||||||
Source="{Binding IconUri, Mode=OneWay}"
|
Source="{Binding IconUri, Mode=OneWay}"
|
||||||
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
||||||
<shci:CachedImage
|
<shci:CachedImage
|
||||||
@@ -317,6 +319,7 @@
|
|||||||
QueryIcon="{cw:FontIconSource Glyph=}"
|
QueryIcon="{cw:FontIconSource Glyph=}"
|
||||||
Style="{StaticResource DefaultTokenizingTextBoxStyle}"
|
Style="{StaticResource DefaultTokenizingTextBoxStyle}"
|
||||||
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
||||||
|
SuggestedItemsSource="{Binding AvailableTokens.Values}"
|
||||||
Text="{Binding FilterToken, Mode=TwoWay}"
|
Text="{Binding FilterToken, Mode=TwoWay}"
|
||||||
TokenItemTemplate="{StaticResource TokenTemplate}">
|
TokenItemTemplate="{StaticResource TokenTemplate}">
|
||||||
<shca:AutoSuggestTokenBox.ItemsPanel>
|
<shca:AutoSuggestTokenBox.ItemsPanel>
|
||||||
|
|||||||
@@ -203,23 +203,19 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</cwc:Case>
|
</cwc:Case>
|
||||||
<cwc:Case Value="Grid">
|
<cwc:Case Value="Grid">
|
||||||
<Border Margin="16,0,16,16" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
<GridView
|
||||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
Padding="16,16,4,4"
|
||||||
<GridView
|
HorizontalAlignment="Stretch"
|
||||||
Padding="16,16,4,4"
|
HorizontalContentAlignment="Left"
|
||||||
HorizontalAlignment="Stretch"
|
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||||
HorizontalContentAlignment="Left"
|
ItemTemplate="{StaticResource MonsterGridTemplate}"
|
||||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
ItemsSource="{Binding Monsters}"
|
||||||
ItemTemplate="{StaticResource MonsterGridTemplate}"
|
SelectedItem="{Binding Selected, Mode=TwoWay}"
|
||||||
ItemsSource="{Binding Monsters}"
|
SelectionMode="Single">
|
||||||
SelectedItem="{Binding Selected, Mode=TwoWay}"
|
<mxi:Interaction.Behaviors>
|
||||||
SelectionMode="Single">
|
<shcb:SelectedItemInViewBehavior/>
|
||||||
<mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
<shcb:SelectedItemInViewBehavior/>
|
</GridView>
|
||||||
</mxi:Interaction.Behaviors>
|
|
||||||
</GridView>
|
|
||||||
</Border>
|
|
||||||
</Border>
|
|
||||||
</cwc:Case>
|
</cwc:Case>
|
||||||
</cwc:SwitchPresenter>
|
</cwc:SwitchPresenter>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -36,33 +36,35 @@
|
|||||||
<DataTemplate x:Key="TokenTemplate">
|
<DataTemplate x:Key="TokenTemplate">
|
||||||
<Grid VerticalAlignment="Center">
|
<Grid VerticalAlignment="Center">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="22"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Ellipse
|
<Rectangle
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="12"
|
Width="4"
|
||||||
Height="12"
|
Height="22"
|
||||||
Margin="1,0,0,0"
|
Margin="0,0,8,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
RadiusX="2"
|
||||||
|
RadiusY="2"
|
||||||
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
Visibility="{Binding Quality, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||||
<Ellipse.Fill>
|
<Rectangle.Fill>
|
||||||
<SolidColorBrush Color="{Binding Quality}"/>
|
<SolidColorBrush Color="{Binding Quality}"/>
|
||||||
</Ellipse.Fill>
|
</Rectangle.Fill>
|
||||||
</Ellipse>
|
</Rectangle>
|
||||||
<shci:MonoChrome
|
<shci:MonoChrome
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="22"
|
Width="22"
|
||||||
Height="22"
|
Height="22"
|
||||||
Margin="-5,2,9,0"
|
Margin="0,0,4,0"
|
||||||
Source="{Binding IconUri, Mode=OneWay}"
|
Source="{Binding IconUri, Mode=OneWay}"
|
||||||
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
||||||
<shci:CachedImage
|
<shci:CachedImage
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="22"
|
Width="22"
|
||||||
Height="22"
|
Height="22"
|
||||||
Margin="-4,0,8,0"
|
Margin="0,0,4,0"
|
||||||
Source="{Binding SideIconUri, Mode=OneWay}"
|
Source="{Binding SideIconUri, Mode=OneWay}"
|
||||||
Visibility="{Binding SideIconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
Visibility="{Binding SideIconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -185,6 +187,7 @@
|
|||||||
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
|
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
|
||||||
QueryIcon="{cw:FontIconSource Glyph=}"
|
QueryIcon="{cw:FontIconSource Glyph=}"
|
||||||
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
SuggestedItemTemplate="{StaticResource TokenTemplate}"
|
||||||
|
SuggestedItemsSource="{Binding AvailableTokens.Values}"
|
||||||
Text="{Binding FilterToken, Mode=TwoWay}"
|
Text="{Binding FilterToken, Mode=TwoWay}"
|
||||||
TokenItemTemplate="{StaticResource TokenTemplate}">
|
TokenItemTemplate="{StaticResource TokenTemplate}">
|
||||||
<shca:AutoSuggestTokenBox.ItemsPanel>
|
<shca:AutoSuggestTokenBox.ItemsPanel>
|
||||||
|
|||||||
@@ -104,14 +104,10 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
|||||||
ArgumentNullException.ThrowIfNull(gachaLogService.ArchiveCollection);
|
ArgumentNullException.ThrowIfNull(gachaLogService.ArchiveCollection);
|
||||||
ObservableCollection<GachaArchive> archives = gachaLogService.ArchiveCollection;
|
ObservableCollection<GachaArchive> archives = gachaLogService.ArchiveCollection;
|
||||||
|
|
||||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
{
|
Archives = archives;
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
HutaoCloudViewModel.RetrieveCommand = RetrieveFromCloudCommand;
|
||||||
Archives = archives;
|
await SetSelectedArchiveAndUpdateStatisticsAsync(Archives.SelectedOrDefault(), true).ConfigureAwait(false);
|
||||||
HutaoCloudViewModel.RetrieveCommand = RetrieveFromCloudCommand;
|
|
||||||
await SetSelectedArchiveAndUpdateStatisticsAsync(Archives.SelectedOrDefault(), true).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,49 +92,39 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
protected override async ValueTask<bool> InitializeUIAsync()
|
protected override async ValueTask<bool> InitializeUIAsync()
|
||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (!await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try
|
return false;
|
||||||
{
|
|
||||||
levelAvatarCurveMap = await metadataService.GetLevelToAvatarCurveMapAsync().ConfigureAwait(false);
|
|
||||||
promotes = await metadataService.GetAvatarPromoteListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
|
||||||
List<Avatar> avatars = await metadataService.GetAvatarListAsync().ConfigureAwait(false);
|
|
||||||
IOrderedEnumerable<Avatar> sorted = avatars
|
|
||||||
.OrderByDescending(avatar => avatar.BeginTime)
|
|
||||||
.ThenByDescending(avatar => avatar.Sort);
|
|
||||||
List<Avatar> list = [.. sorted];
|
|
||||||
|
|
||||||
await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false);
|
|
||||||
|
|
||||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
Avatars = new(list, true);
|
|
||||||
Selected = Avatars.View.ElementAtOrDefault(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterTokens = [];
|
|
||||||
|
|
||||||
availableTokens = FrozenDictionary.ToFrozenDictionary(
|
|
||||||
[
|
|
||||||
.. avatars.Select(avatar => KeyValuePair.Create(avatar.Name, new SearchToken(SearchTokenKind.Avatar, avatar.Name, sideIconUri: AvatarSideIconConverter.IconNameToUri(avatar.SideIcon)))),
|
|
||||||
.. IntrinsicFrozen.AssociationTypes.Select(assoc => KeyValuePair.Create(assoc, new SearchToken(SearchTokenKind.AssociationType, assoc, iconUri: AssociationTypeIconConverter.AssociationTypeNameToIconUri(assoc)))),
|
|
||||||
.. IntrinsicFrozen.BodyTypes.Select(b => KeyValuePair.Create(b, new SearchToken(SearchTokenKind.BodyType, b))),
|
|
||||||
.. IntrinsicFrozen.ElementNames.Select(e => KeyValuePair.Create(e, new SearchToken(SearchTokenKind.ElementName, e, iconUri: ElementNameIconConverter.ElementNameToIconUri(e)))),
|
|
||||||
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
|
|
||||||
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
levelAvatarCurveMap = await metadataService.GetLevelToAvatarCurveMapAsync().ConfigureAwait(false);
|
||||||
|
promotes = await metadataService.GetAvatarPromoteListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
||||||
|
List<Avatar> avatars = await metadataService.GetAvatarListAsync().ConfigureAwait(false);
|
||||||
|
IOrderedEnumerable<Avatar> sorted = avatars
|
||||||
|
.OrderByDescending(avatar => avatar.BeginTime)
|
||||||
|
.ThenByDescending(avatar => avatar.Sort);
|
||||||
|
List<Avatar> list = [.. sorted];
|
||||||
|
|
||||||
|
await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
Avatars = new(list, true);
|
||||||
|
Selected = Avatars.View.ElementAtOrDefault(0);
|
||||||
|
FilterTokens = [];
|
||||||
|
|
||||||
|
availableTokens = FrozenDictionary.ToFrozenDictionary(
|
||||||
|
[
|
||||||
|
.. avatars.Select(avatar => KeyValuePair.Create(avatar.Name, new SearchToken(SearchTokenKind.Avatar, avatar.Name, sideIconUri: AvatarSideIconConverter.IconNameToUri(avatar.SideIcon)))),
|
||||||
|
.. IntrinsicFrozen.AssociationTypes.Select(assoc => KeyValuePair.Create(assoc, new SearchToken(SearchTokenKind.AssociationType, assoc, iconUri: AssociationTypeIconConverter.AssociationTypeNameToIconUri(assoc)))),
|
||||||
|
.. IntrinsicFrozen.BodyTypes.Select(b => KeyValuePair.Create(b, new SearchToken(SearchTokenKind.BodyType, b))),
|
||||||
|
.. IntrinsicFrozen.ElementNames.Select(e => KeyValuePair.Create(e, new SearchToken(SearchTokenKind.ElementName, e, iconUri: ElementNameIconConverter.ElementNameToIconUri(e)))),
|
||||||
|
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
|
||||||
|
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask CombineComplexDataAsync(List<Avatar> avatars, Dictionary<MaterialId, Material> idMaterialMap)
|
private async ValueTask CombineComplexDataAsync(List<Avatar> avatars, Dictionary<MaterialId, Material> idMaterialMap)
|
||||||
|
|||||||
@@ -53,31 +53,21 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel
|
|||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try
|
levelMonsterCurveMap = await metadataService.GetLevelToMonsterCurveMapAsync().ConfigureAwait(false);
|
||||||
{
|
|
||||||
levelMonsterCurveMap = await metadataService.GetLevelToMonsterCurveMapAsync().ConfigureAwait(false);
|
List<Monster> monsters = await metadataService.GetMonsterListAsync().ConfigureAwait(false);
|
||||||
|
Dictionary<MaterialId, DisplayItem> idDisplayMap = await metadataService.GetIdToDisplayItemAndMaterialMapAsync().ConfigureAwait(false);
|
||||||
List<Monster> monsters = await metadataService.GetMonsterListAsync().ConfigureAwait(false);
|
foreach (Monster monster in monsters)
|
||||||
Dictionary<MaterialId, DisplayItem> idDisplayMap = await metadataService.GetIdToDisplayItemAndMaterialMapAsync().ConfigureAwait(false);
|
|
||||||
foreach (Monster monster in monsters)
|
|
||||||
{
|
|
||||||
monster.DropsView ??= monster.Drops?.SelectList(i => idDisplayMap.GetValueOrDefault(i, Material.Default));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Monster> ordered = monsters.SortBy(m => m.RelationshipId.Value);
|
|
||||||
|
|
||||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
Monsters = new(ordered, true);
|
|
||||||
Selected = Monsters.View.ElementAtOrDefault(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
{
|
||||||
|
monster.DropsView ??= monster.Drops?.SelectList(i => idDisplayMap.GetValueOrDefault(i, Material.Default));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Monster> ordered = monsters.SortBy(m => m.RelationshipId.Value);
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
|
||||||
|
Monsters = new(ordered, true);
|
||||||
|
Selected = Monsters.View.ElementAtOrDefault(0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -92,42 +92,32 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
|
|||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try
|
levelWeaponCurveMap = await metadataService.GetLevelToWeaponCurveMapAsync().ConfigureAwait(false);
|
||||||
{
|
promotes = await metadataService.GetWeaponPromoteListAsync().ConfigureAwait(false);
|
||||||
levelWeaponCurveMap = await metadataService.GetLevelToWeaponCurveMapAsync().ConfigureAwait(false);
|
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
||||||
promotes = await metadataService.GetWeaponPromoteListAsync().ConfigureAwait(false);
|
|
||||||
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
List<Weapon> weapons = await metadataService.GetWeaponListAsync().ConfigureAwait(false);
|
List<Weapon> weapons = await metadataService.GetWeaponListAsync().ConfigureAwait(false);
|
||||||
IEnumerable<Weapon> sorted = weapons
|
IEnumerable<Weapon> sorted = weapons
|
||||||
.OrderByDescending(weapon => weapon.RankLevel)
|
.OrderByDescending(weapon => weapon.RankLevel)
|
||||||
.ThenBy(weapon => weapon.WeaponType)
|
.ThenBy(weapon => weapon.WeaponType)
|
||||||
.ThenByDescending(weapon => weapon.Id.Value);
|
.ThenByDescending(weapon => weapon.Id.Value);
|
||||||
List<Weapon> list = [.. sorted];
|
List<Weapon> list = [.. sorted];
|
||||||
|
|
||||||
await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false);
|
await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false);
|
||||||
|
|
||||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
{
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
|
|
||||||
Weapons = new(list, true);
|
Weapons = new(list, true);
|
||||||
Selected = Weapons.View.ElementAtOrDefault(0);
|
Selected = Weapons.View.ElementAtOrDefault(0);
|
||||||
}
|
FilterTokens = [];
|
||||||
|
|
||||||
FilterTokens = [];
|
availableTokens = FrozenDictionary.ToFrozenDictionary(
|
||||||
|
[
|
||||||
availableTokens = FrozenDictionary.ToFrozenDictionary(
|
.. weapons.Select(w => KeyValuePair.Create(w.Name, new SearchToken(SearchTokenKind.Weapon, w.Name, sideIconUri: EquipIconConverter.IconNameToUri(w.Icon)))),
|
||||||
[
|
.. IntrinsicFrozen.FightProperties.Select(f => KeyValuePair.Create(f, new SearchToken(SearchTokenKind.FightProperty, f))),
|
||||||
.. weapons.Select(w => KeyValuePair.Create(w.Name, new SearchToken(SearchTokenKind.Weapon, w.Name, sideIconUri: EquipIconConverter.IconNameToUri(w.Icon)))),
|
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
|
||||||
.. IntrinsicFrozen.FightProperties.Select(f => KeyValuePair.Create(f, new SearchToken(SearchTokenKind.FightProperty, f))),
|
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
|
||||||
.. IntrinsicFrozen.ItemQualities.Select(i => KeyValuePair.Create(i, new SearchToken(SearchTokenKind.ItemQuality, i, quality: QualityColorConverter.QualityNameToColor(i)))),
|
]);
|
||||||
.. IntrinsicFrozen.WeaponTypes.Select(w => KeyValuePair.Create(w, new SearchToken(SearchTokenKind.WeaponType, w, iconUri: WeaponTypeIconConverter.WeaponTypeNameToIconUri(w)))),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
|
||||||
|
|
||||||
internal static class LatestPackageExtension
|
|
||||||
{
|
|
||||||
public static void Patch(this LatestPackage latest)
|
|
||||||
{
|
|
||||||
StringBuilder pathBuilder = new();
|
|
||||||
foreach (PackageSegment segment in latest.Segments)
|
|
||||||
{
|
|
||||||
pathBuilder.AppendLine(segment.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
latest.Path = pathBuilder.ToStringTrimEndReturn();
|
|
||||||
latest.Name = Path.GetFileName(latest.Segments[0].Path[..^4]); // .00X
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -46,16 +46,18 @@ internal sealed partial class ResourceClient
|
|||||||
.TryCatchSendAsync<Response<GameResource>>(httpClient, logger, token)
|
.TryCatchSendAsync<Response<GameResource>>(httpClient, logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// 最新版完整包
|
// 补全缺失的信息
|
||||||
if (resp is { Data.Game.Latest: LatestPackage latest })
|
if (resp is { Data.Game.Latest: LatestPackage latest })
|
||||||
{
|
{
|
||||||
latest.Patch();
|
StringBuilder pathBuilder = new();
|
||||||
}
|
foreach (PackageSegment segment in latest.Segments)
|
||||||
|
{
|
||||||
|
pathBuilder.AppendLine(segment.Path);
|
||||||
|
}
|
||||||
|
|
||||||
// 预下载完整包
|
latest.Path = pathBuilder.ToStringTrimEndReturn();
|
||||||
if (resp is { Data.PreDownloadGame.Latest: LatestPackage preDownloadLatest })
|
string path = latest.Segments[0].Path[..^4]; // .00X
|
||||||
{
|
latest.Name = Path.GetFileName(path);
|
||||||
preDownloadLatest.Patch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response.Response.DefaultIfNull(resp);
|
return Response.Response.DefaultIfNull(resp);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
|
|
||||||
namespace Snap.Hutao.Win32;
|
namespace Snap.Hutao.Win32;
|
||||||
@@ -27,26 +26,45 @@ internal static class StructMarshal
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Rect Rect(Vector2 size)
|
/// <summary>
|
||||||
{
|
/// 从 0,0 点构造一个新的<see cref="Windows.Graphics.RectInt32"/>
|
||||||
return new(0, 0, size.X, size.Y);
|
/// </summary>
|
||||||
}
|
/// <param name="size">尺寸</param>
|
||||||
|
/// <returns>新的实例</returns>
|
||||||
public static RectInt32 RectInt32(SizeInt32 size)
|
public static RectInt32 RectInt32(SizeInt32 size)
|
||||||
{
|
{
|
||||||
return new(0, 0, size.Width, size.Height);
|
return new(0, 0, size.Width, size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的<see cref="Windows.Graphics.RectInt32"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">左上角位置</param>
|
||||||
|
/// <param name="size">尺寸</param>
|
||||||
|
/// <returns>新的实例</returns>
|
||||||
public static RectInt32 RectInt32(PointInt32 point, Vector2 size)
|
public static RectInt32 RectInt32(PointInt32 point, Vector2 size)
|
||||||
{
|
{
|
||||||
return RectInt32(point.X, point.Y, size);
|
return RectInt32(point.X, point.Y, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的<see cref="Windows.Graphics.RectInt32"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">X</param>
|
||||||
|
/// <param name="y">Y</param>
|
||||||
|
/// <param name="size">尺寸</param>
|
||||||
|
/// <returns>新的实例</returns>
|
||||||
public static RectInt32 RectInt32(int x, int y, Vector2 size)
|
public static RectInt32 RectInt32(int x, int y, Vector2 size)
|
||||||
{
|
{
|
||||||
return new(x, y, (int)size.X, (int)size.Y);
|
return new(x, y, (int)size.X, (int)size.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的<see cref="Windows.Graphics.RectInt32"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">左上角位置</param>
|
||||||
|
/// <param name="size">尺寸</param>
|
||||||
|
/// <returns>新的实例</returns>
|
||||||
public static RectInt32 RectInt32(PointInt32 point, SizeInt32 size)
|
public static RectInt32 RectInt32(PointInt32 point, SizeInt32 size)
|
||||||
{
|
{
|
||||||
return new(point.X, point.Y, size.Width, size.Height);
|
return new(point.X, point.Y, size.Width, size.Height);
|
||||||
|
|||||||
Reference in New Issue
Block a user