Merge pull request #944 from DGP-Studio/develop

This commit is contained in:
DismissedLight
2023-09-20 13:36:31 +08:00
committed by GitHub
154 changed files with 4469 additions and 2008 deletions

View File

@@ -0,0 +1,147 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.CodeAnalysis;
namespace Snap.Hutao.SourceGeneration.Automation;
[Generator(LanguageNames.CSharp)]
internal sealed class AttributeGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(GenerateAllAttributes);
}
public static void GenerateAllAttributes(IncrementalGeneratorPostInitializationContext context)
{
string coreAnnotations = """
using System.Diagnostics;
namespace Snap.Hutao.Core.Annotation;
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class CommandAttribute : Attribute
{
public CommandAttribute(string name)
{
}
public bool AllowConcurrentExecutions { get; set; }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class ConstructorGeneratedAttribute : Attribute
{
public ConstructorGeneratedAttribute()
{
}
public bool CallBaseConstructor { get; set; }
public bool ResolveHttpClient { get; set; }
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class DependencyPropertyAttribute : Attribute
{
public DependencyPropertyAttribute(string name, Type type)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue, string valueChangedCallbackName)
{
}
public bool IsAttached { get; set; }
public Type AttachedType { get; set; } = default;
}
[AttributeUsage(AttributeTargets.All, Inherited = false)]
[Conditional("DEBUG")]
internal sealed class HighQualityAttribute : Attribute
{
}
""";
context.AddSource("Snap.Hutao.Core.Annotation.Attributes.g.cs", coreAnnotations);
string coreDependencyInjectionAnnotationHttpClients = """
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class HttpClientAttribute : Attribute
{
public HttpClientAttribute(HttpClientConfiguration configuration)
{
}
public HttpClientAttribute(HttpClientConfiguration configuration, Type interfaceType)
{
}
}
internal enum HttpClientConfiguration
{
/// <summary>
/// 默认配置
/// </summary>
Default,
/// <summary>
/// 米游社请求配置
/// </summary>
XRpc,
/// <summary>
/// 米游社登录请求配置
/// </summary>
XRpc2,
/// <summary>
/// Hoyolab app
/// </summary>
XRpc3,
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class PrimaryHttpMessageHandlerAttribute : Attribute
{
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.MaxConnectionsPerServer"/>
public int MaxConnectionsPerServer { get; set; }
/// <summary>
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.UseCookies"/>
/// </summary>
public bool UseCookies { get; set; }
}
""";
context.AddSource("Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient.Attributes.g.cs", coreDependencyInjectionAnnotationHttpClients);
string coreDependencyInjectionAnnotations = """
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
internal enum InjectAs
{
Singleton,
Transient,
Scoped,
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class InjectionAttribute : Attribute
{
public InjectionAttribute(InjectAs injectAs)
{
}
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
{
}
}
""";
context.AddSource("Snap.Hutao.Core.DependencyInjection.Annotation.Attributes.g.cs", coreDependencyInjectionAnnotations);
}
}

View File

@@ -95,4 +95,4 @@ internal sealed class CommandGenerator : IIncrementalGenerator
string normalizedClassName = classSymbol.ToDisplayString().Replace('<', '{').Replace('>', '}');
production.AddSource($"{normalizedClassName}.{commandName}.g.cs", code);
}
}
}

View File

@@ -0,0 +1,61 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.CodeAnalysis;
using System.Net.Http;
using System.Runtime.Serialization;
namespace Snap.Hutao.SourceGeneration.Automation;
[Generator(LanguageNames.CSharp)]
internal sealed class SaltConstantGenerator : IIncrementalGenerator
{
private static readonly HttpClient httpClient = new();
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(GenerateSaltContstants);
}
private static void GenerateSaltContstants(IncrementalGeneratorPostInitializationContext context)
{
string body = httpClient.GetStringAsync("https://internal.snapgenshin.cn/Archive/Salt/Latest").GetAwaiter().GetResult();
Response<SaltLatest> saltInfo = JsonParser.FromJson<Response<SaltLatest>>(body)!;
string code = $$"""
namespace Snap.Hutao.Web.Hoyolab;
internal sealed class SaltConstants
{
public const string CNVersion = "{{saltInfo.Data.CNVersion}}";
public const string CNK2 = "{{saltInfo.Data.CNK2}}";
public const string CNLK2 = "{{saltInfo.Data.CNLK2}}";
public const string OSVersion = "{{saltInfo.Data.OSVersion}}";
public const string OSK2 = "{{saltInfo.Data.OSK2}}";
public const string OSLK2 = "{{saltInfo.Data.OSLK2}}";
}
""";
context.AddSource("SaltConstants.g.cs", code);
}
private sealed class Response<T>
{
[DataMember(Name = "data")]
public T Data { get; set; } = default!;
}
internal sealed class SaltLatest
{
public string CNVersion { get; set; } = default!;
public string CNK2 { get; set; } = default!;
public string CNLK2 { get; set; } = default!;
public string OSVersion { get; set; } = default!;
public string OSK2 { get; set; } = default!;
public string OSLK2 { get; set; } = default!;
}
}

View File

@@ -8,7 +8,10 @@ internal sealed class NotNullWhenAttribute : Attribute
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }

View File

@@ -89,6 +89,12 @@ internal sealed class IdentityGenerator : IIncrementalGenerator
{
return Value.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
return Value.ToString();
}
}
""");

View File

@@ -49,7 +49,7 @@ public class JsonSerializeTest
NumberHandling = JsonNumberHandling.AllowReadingFromString,
};
Dictionary<int,string> sample = JsonSerializer.Deserialize<Dictionary<int, string>>(SmapleNumberKeyDictionaryJson, options)!;
Dictionary<int, string> sample = JsonSerializer.Deserialize<Dictionary<int, string>>(SmapleNumberKeyDictionaryJson, options)!;
Assert.AreEqual(sample[111], "12");
}

View File

@@ -2,8 +2,8 @@
x:Class="Snap.Hutao.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwc="using:CommunityToolkit.WinUI.Converters"
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
@@ -13,6 +13,7 @@
<ResourceDictionary.MergedDictionaries>
<muxc:XamlControlsResources/>
<ResourceDictionary Source="Control/Theme/FontStyle.xaml"/>
<ResourceDictionary Source="Control/Loading.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
@@ -117,9 +118,9 @@
<x:String x:Key="FontIconContentAsteriskBadge12">&#xEDAD;</x:String>
<x:String x:Key="FontIconContentZipFolder">&#xF012;</x:String>
<!-- Converters -->
<cwuc:BoolNegationConverter x:Key="BoolNegationConverter"/>
<cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cwuc:FileSizeToFriendlyStringConverter x:Key="FileSizeToFriendlyStringConverter"/>
<cwc:BoolNegationConverter x:Key="BoolNegationConverter"/>
<cwc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cwc:FileSizeToFriendlyStringConverter x:Key="FileSizeToFriendlyStringConverter"/>
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
<shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/>
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>

View File

@@ -14,12 +14,36 @@ namespace Snap.Hutao.Control.Behavior;
[DependencyProperty("CommandParameter", typeof(object))]
internal sealed partial class InvokeCommandOnLoadedBehavior : BehaviorBase<UIElement>
{
private bool executed;
protected override void OnAttached()
{
base.OnAttached();
// FrameworkElement in a ItemsRepeater gets attached twice
if (AssociatedObject is FrameworkElement { IsLoaded: true })
{
TryExecuteCommand();
}
}
/// <inheritdoc/>
protected override void OnAssociatedObjectLoaded()
{
TryExecuteCommand();
}
private void TryExecuteCommand()
{
if (executed)
{
return;
}
if (Command is not null && Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
executed = true;
}
}
}

View File

@@ -11,8 +11,8 @@ public sealed partial class FrameworkElementHelper
{
private static void OnSquareLengthChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
Microsoft.UI.Xaml.Controls.Control control = (Microsoft.UI.Xaml.Controls.Control)dp;
control.Width = (double)e.NewValue;
control.Height = (double)e.NewValue;
FrameworkElement element = (FrameworkElement)dp;
element.Width = (double)e.NewValue;
element.Height = (double)e.NewValue;
}
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("IsTextSelectionEnabled", typeof(bool), false, IsAttached = true, AttachedType = typeof(InfoBar))]
public sealed partial class InfoBarHelper
{
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Snap.Hutao.Core.Caching;
@@ -13,7 +12,7 @@ namespace Snap.Hutao.Control.Image;
/// 缓存图像
/// </summary>
[HighQuality]
internal sealed class CachedImage : ImageEx
internal sealed class CachedImage : Implementation.ImageEx
{
/// <summary>
/// 构造一个新的缓存图像

View File

@@ -0,0 +1,44 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Windows.Media.Casting;
namespace Snap.Hutao.Control.Image.Implementation;
internal class ImageEx : ImageExBase
{
private static readonly DependencyProperty NineGridProperty = DependencyProperty.Register(nameof(NineGrid), typeof(Thickness), typeof(ImageEx), new PropertyMetadata(default(Thickness)));
public ImageEx()
: base()
{
}
public Thickness NineGrid
{
get => (Thickness)GetValue(NineGridProperty);
set => SetValue(NineGridProperty, value);
}
public override CompositionBrush GetAlphaMask()
{
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
{
return image.GetAlphaMask();
}
return default!;
}
public CastingSource GetAsCastingSource()
{
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
{
return image.GetAsCastingSource();
}
return default!;
}
}

View File

@@ -0,0 +1,468 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using System.IO;
using Windows.Foundation;
namespace Snap.Hutao.Control.Image.Implementation;
internal delegate void ImageExFailedEventHandler(object sender, ImageExFailedEventArgs e);
internal delegate void ImageExOpenedEventHandler(object sender, ImageExOpenedEventArgs e);
[SuppressMessage("", "CA1001")]
[SuppressMessage("", "SH003")]
[TemplateVisualState(Name = LoadingState, GroupName = CommonGroup)]
[TemplateVisualState(Name = LoadedState, GroupName = CommonGroup)]
[TemplateVisualState(Name = UnloadedState, GroupName = CommonGroup)]
[TemplateVisualState(Name = FailedState, GroupName = CommonGroup)]
[TemplatePart(Name = PartImage, Type = typeof(object))]
internal abstract class ImageExBase : Microsoft.UI.Xaml.Controls.Control, IAlphaMaskProvider
{
protected const string PartImage = "Image";
protected const string CommonGroup = "CommonStates";
protected const string LoadingState = "Loading";
protected const string LoadedState = "Loaded";
protected const string UnloadedState = "Unloaded";
protected const string FailedState = "Failed";
private static readonly DependencyProperty StretchProperty = DependencyProperty.Register(nameof(Stretch), typeof(Stretch), typeof(ImageExBase), new PropertyMetadata(Stretch.Uniform));
private static readonly DependencyProperty DecodePixelHeightProperty = DependencyProperty.Register(nameof(DecodePixelHeight), typeof(int), typeof(ImageExBase), new PropertyMetadata(0));
private static readonly DependencyProperty DecodePixelTypeProperty = DependencyProperty.Register(nameof(DecodePixelType), typeof(int), typeof(ImageExBase), new PropertyMetadata(DecodePixelType.Physical));
private static readonly DependencyProperty DecodePixelWidthProperty = DependencyProperty.Register(nameof(DecodePixelWidth), typeof(int), typeof(ImageExBase), new PropertyMetadata(0));
private static readonly DependencyProperty IsCacheEnabledProperty = DependencyProperty.Register(nameof(IsCacheEnabled), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false));
private static readonly DependencyProperty EnableLazyLoadingProperty = DependencyProperty.Register(nameof(EnableLazyLoading), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false, EnableLazyLoadingChanged));
private static readonly DependencyProperty LazyLoadingThresholdProperty = DependencyProperty.Register(nameof(LazyLoadingThreshold), typeof(double), typeof(ImageExBase), new PropertyMetadata(default(double), LazyLoadingThresholdChanged));
private static readonly DependencyProperty PlaceholderSourceProperty = DependencyProperty.Register(nameof(PlaceholderSource), typeof(ImageSource), typeof(ImageExBase), new PropertyMetadata(default(ImageSource), PlaceholderSourceChanged));
private static readonly DependencyProperty PlaceholderStretchProperty = DependencyProperty.Register(nameof(PlaceholderStretch), typeof(Stretch), typeof(ImageExBase), new PropertyMetadata(default(Stretch)));
private static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source), typeof(object), typeof(ImageExBase), new PropertyMetadata(null, SourceChanged));
private CancellationTokenSource? tokenSource;
private object? lazyLoadingSource;
private bool isInViewport;
public event ImageExFailedEventHandler? ImageExFailed;
public event ImageExOpenedEventHandler? ImageExOpened;
public event EventHandler? ImageExInitialized;
public bool IsInitialized { get; private set; }
public int DecodePixelHeight
{
get => (int)GetValue(DecodePixelHeightProperty);
set => SetValue(DecodePixelHeightProperty, value);
}
public DecodePixelType DecodePixelType
{
get => (DecodePixelType)GetValue(DecodePixelTypeProperty);
set => SetValue(DecodePixelTypeProperty, value);
}
public int DecodePixelWidth
{
get => (int)GetValue(DecodePixelWidthProperty);
set => SetValue(DecodePixelWidthProperty, value);
}
public Stretch Stretch
{
get => (Stretch)GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
public bool IsCacheEnabled
{
get => (bool)GetValue(IsCacheEnabledProperty);
set => SetValue(IsCacheEnabledProperty, value);
}
public bool EnableLazyLoading
{
get => (bool)GetValue(EnableLazyLoadingProperty);
set => SetValue(EnableLazyLoadingProperty, value);
}
public double LazyLoadingThreshold
{
get => (double)GetValue(LazyLoadingThresholdProperty);
set => SetValue(LazyLoadingThresholdProperty, value);
}
public ImageSource PlaceholderSource
{
get => (ImageSource)GetValue(PlaceholderSourceProperty);
set => SetValue(PlaceholderSourceProperty, value);
}
public Stretch PlaceholderStretch
{
get => (Stretch)GetValue(PlaceholderStretchProperty);
set => SetValue(PlaceholderStretchProperty, value);
}
public object Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
public bool WaitUntilLoaded
{
get => true;
}
protected object? Image { get; private set; }
public abstract CompositionBrush GetAlphaMask();
protected virtual void OnPlaceholderSourceChanged(DependencyPropertyChangedEventArgs e)
{
}
protected virtual Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
{
// By default we just use the built-in UWP image cache provided within the Image control.
return Task.FromResult<ImageSource?>(new BitmapImage(imageUri));
}
protected virtual void OnImageOpened(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToState(this, LoadedState, true);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
}
protected virtual void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new FileNotFoundException(e.ErrorMessage)));
}
protected void AttachImageOpened(RoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageOpened += handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageOpened += handler;
}
}
protected void RemoveImageOpened(RoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageOpened -= handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageOpened -= handler;
}
}
protected void AttachImageFailed(ExceptionRoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageFailed += handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageFailed += handler;
}
}
protected void RemoveImageFailed(ExceptionRoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageFailed -= handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageFailed -= handler;
}
}
protected override void OnApplyTemplate()
{
RemoveImageOpened(OnImageOpened);
RemoveImageFailed(OnImageFailed);
Image = GetTemplateChild(PartImage);
IsInitialized = true;
ImageExInitialized?.Invoke(this, EventArgs.Empty);
if (Source is null || !EnableLazyLoading || isInViewport)
{
lazyLoadingSource = null;
SetSource(Source);
}
else
{
lazyLoadingSource = Source;
}
AttachImageOpened(OnImageOpened);
AttachImageFailed(OnImageFailed);
base.OnApplyTemplate();
}
private static void EnableLazyLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
bool value = (bool)e.NewValue;
if (value)
{
control.LayoutUpdated += control.ImageExBase_LayoutUpdated;
control.InvalidateLazyLoading();
}
else
{
control.LayoutUpdated -= control.ImageExBase_LayoutUpdated;
}
}
}
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control && control.EnableLazyLoading)
{
control.InvalidateLazyLoading();
}
}
private static void PlaceholderSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
control.OnPlaceholderSourceChanged(e);
}
}
private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not ImageExBase control)
{
return;
}
if (e.OldValue is null || e.NewValue is null || !e.OldValue.Equals(e.NewValue))
{
if (e.NewValue is null || !control.EnableLazyLoading || control.isInViewport)
{
control.lazyLoadingSource = null;
control.SetSource(e.NewValue);
}
else
{
control.lazyLoadingSource = e.NewValue;
}
}
}
private static bool IsHttpUri(Uri uri)
{
return uri.IsAbsoluteUri && (uri.Scheme == "http" || uri.Scheme == "https");
}
private void AttachSource(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 (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.Source = source;
}
else if (Image is ImageBrush brush)
{
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);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
}
}
[SuppressMessage("", "IDE0019")]
private async void SetSource(object? source)
{
if (!IsInitialized)
{
return;
}
tokenSource?.Cancel();
tokenSource = new CancellationTokenSource();
AttachSource(null);
if (source is null)
{
return;
}
VisualStateManager.GoToState(this, LoadingState, true);
ImageSource? imageSource = source as ImageSource;
if (imageSource is not null)
{
AttachSource(imageSource);
return;
}
Uri? uri = source as Uri;
if (uri is null)
{
string? url = source as string ?? source.ToString();
if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri))
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new UriFormatException("Invalid uri specified.")));
return;
}
}
if (!IsHttpUri(uri) && !uri.IsAbsoluteUri)
{
uri = new Uri("ms-appx:///" + uri.OriginalString.TrimStart('/'));
}
try
{
await LoadImageAsync(uri, tokenSource.Token).ConfigureAwait(true);
}
catch (OperationCanceledException)
{
// nothing to do as cancellation has been requested.
}
catch (Exception e)
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
}
}
private async Task LoadImageAsync(Uri imageUri, CancellationToken token)
{
if (imageUri is not null)
{
if (IsCacheEnabled)
{
ImageSource? img = await ProvideCachedResourceAsync(imageUri, token).ConfigureAwait(true);
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
// Only attach our image if we still have a valid request.
AttachSource(img);
}
}
else if (string.Equals(imageUri.Scheme, "data", StringComparison.OrdinalIgnoreCase))
{
string source = imageUri.OriginalString;
const string base64Head = "base64,";
int index = source.IndexOf(base64Head, StringComparison.Ordinal);
if (index >= 0)
{
byte[] bytes = Convert.FromBase64String(source[(index + base64Head.Length)..]);
BitmapImage bitmap = new();
await bitmap.SetSourceAsync(new MemoryStream(bytes).AsRandomAccessStream());
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
AttachSource(bitmap);
}
}
}
else
{
AttachSource(new BitmapImage(imageUri)
{
CreateOptions = BitmapCreateOptions.IgnoreImageCache,
});
}
}
}
private void ImageExBase_LayoutUpdated(object? sender, object e)
{
InvalidateLazyLoading();
}
private void InvalidateLazyLoading()
{
if (!IsLoaded)
{
isInViewport = false;
return;
}
// Find the first ascendant ScrollViewer, if not found, use the root element.
FrameworkElement? hostElement = default;
IEnumerable<FrameworkElement> ascendants = this.FindAscendants().OfType<FrameworkElement>();
foreach (FrameworkElement ascendant in ascendants)
{
hostElement = ascendant;
if (hostElement is Microsoft.UI.Xaml.Controls.ScrollViewer)
{
break;
}
}
if (hostElement is null)
{
isInViewport = false;
return;
}
Rect controlRect = TransformToVisual(hostElement)
.TransformBounds(new Rect(0, 0, ActualWidth, ActualHeight));
double lazyLoadingThreshold = LazyLoadingThreshold;
Rect hostRect = new(
0 - lazyLoadingThreshold,
0 - lazyLoadingThreshold,
hostElement.ActualWidth + (2 * lazyLoadingThreshold),
hostElement.ActualHeight + (2 * lazyLoadingThreshold));
if (controlRect.IntersectsWith(hostRect))
{
isInViewport = true;
if (lazyLoadingSource is not null)
{
object source = lazyLoadingSource;
lazyLoadingSource = null;
SetSource(source);
}
}
else
{
isInViewport = false;
}
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Image.Implementation;
internal sealed class ImageExFailedEventArgs : EventArgs
{
public ImageExFailedEventArgs(Exception errorException)
{
ErrorMessage = ErrorException?.Message;
ErrorException = errorException;
}
public Exception? ErrorException { get; private set; }
public string? ErrorMessage { get; private set; }
}

View File

@@ -0,0 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Image.Implementation;
internal sealed class ImageExOpenedEventArgs : EventArgs
{
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.Control;
[TemplateVisualState(Name = "LoadingIn", GroupName = "CommonStates")]
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
{
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(Loading), new PropertyMetadata(default(bool), IsLoadingPropertyChanged));
[SuppressMessage("", "IDE0052")]
private FrameworkElement? presenter;
public Loading()
{
DefaultStyleKey = typeof(Loading);
DefaultStyleResourceUri = new("ms-appx:///Control/Loading.xaml");
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
Update();
}
private static void IsLoadingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Loading control = (Loading)d;
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
control?.Update();
}
private void Update()
{
VisualStateManager.GoToState(this, IsLoading ? "LoadingIn" : "LoadingOut", true);
}
}

View File

@@ -0,0 +1,85 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shc="using:Snap.Hutao.Control">
<Style TargetType="shc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="shc:Loading">
<Border
x:Name="RootGrid"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Opacity="0"
Visibility="Collapsed">
<ContentPresenter
x:Name="ContentGrid"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter.RenderTransform>
<CompositeTransform/>
</ContentPresenter.RenderTransform>
</ContentPresenter>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="LoadingIn">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LoadingOut">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Media;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using Windows.UI;

View File

@@ -39,7 +39,7 @@ internal struct Rgba32
/// </summary>
/// <param name="hex">色值字符串</param>
public Rgba32(string hex)
: this(Convert.ToUInt32(hex, 16))
: this(hex.Length == 6 ? Convert.ToUInt32($"{hex}FF", 16) : Convert.ToUInt32(hex, 16))
{
}

View File

@@ -20,6 +20,7 @@ namespace Snap.Hutao.Control.Text;
/// </summary>
[HighQuality]
[DependencyProperty("Description", typeof(string), "", nameof(OnDescriptionChanged))]
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
internal sealed partial class DescriptionTextBlock : ContentControl
{
private static readonly int ColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
@@ -40,6 +41,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl
Content = new TextBlock()
{
TextWrapping = TextWrapping.Wrap,
Style = TextStyle,
};
actualThemeChangedEventHandler = OnActualThemeChanged;
@@ -54,6 +56,12 @@ internal sealed partial class DescriptionTextBlock : ContentControl
UpdateDescription(textBlock, description);
}
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((DescriptionTextBlock)d).Content;
textBlock.Style = (Style)e.NewValue;
}
private static void UpdateDescription(TextBlock textBlock, in ReadOnlySpan<char> description)
{
textBlock.Inlines.Clear();
@@ -66,7 +74,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl
{
AppendText(textBlock, description[last..i]);
AppendLineBreak(textBlock);
i += 1;
i += 2;
last = i;
}

View File

@@ -0,0 +1,182 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Control.Media;
using Snap.Hutao.Control.Theme;
using Windows.Foundation;
using Windows.UI;
namespace Snap.Hutao.Control.Text;
[DependencyProperty("Description", typeof(string), "", nameof(OnDescriptionChanged))]
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
internal sealed partial class HtmlDescriptionTextBlock : ContentControl
{
private static readonly int ColorTagFullLength = "<color style='color:#FFFFFF;'></color>".Length;
private static readonly int ColorTagLeftLength = "<color style='color:#FFFFFF;'>".Length;
private static readonly int ItalicTagFullLength = "<i></i>".Length;
private static readonly int ItalicTagLeftLength = "<i>".Length;
private static readonly int BoldTagFullLength = "<b></b>".Length;
private static readonly int BoldTagLeftLength = "<b>".Length;
private readonly TypedEventHandler<FrameworkElement, object> actualThemeChangedEventHandler;
/// <summary>
/// 构造一个新的呈现描述文本的文本块
/// </summary>
public HtmlDescriptionTextBlock()
{
this.DisableInteraction();
Content = new TextBlock()
{
TextWrapping = TextWrapping.Wrap,
Style = TextStyle,
};
actualThemeChangedEventHandler = OnActualThemeChanged;
ActualThemeChanged += actualThemeChangedEventHandler;
}
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((HtmlDescriptionTextBlock)d).Content;
ReadOnlySpan<char> description = (string)e.NewValue;
UpdateDescription(textBlock, description);
}
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((HtmlDescriptionTextBlock)d).Content;
textBlock.Style = (Style)e.NewValue;
}
private static void UpdateDescription(TextBlock textBlock, in ReadOnlySpan<char> description)
{
textBlock.Inlines.Clear();
int last = 0;
for (int i = 0; i < description.Length;)
{
// newline
if (description[i..].StartsWith(@"<br>"))
{
AppendText(textBlock, description[last..i]);
AppendLineBreak(textBlock);
i += 4;
last = i;
}
// color tag
else if (description[i..].StartsWith("<c"))
{
AppendText(textBlock, description[last..i]);
string a = description.Slice(i + 21, 6).ToString();
Rgba32 color = new(a);
int length = description[(i + ColorTagLeftLength)..].IndexOf('<');
AppendColorText(textBlock, description.Slice(i + ColorTagLeftLength, length), color);
i += length + ColorTagFullLength;
last = i;
}
// italic
else if (description[i..].StartsWith("<i"))
{
AppendText(textBlock, description[last..i]);
int length = description[(i + ItalicTagLeftLength)..].IndexOf('<');
AppendItalicText(textBlock, description.Slice(i + ItalicTagLeftLength, length));
i += length + ItalicTagFullLength;
last = i;
}
// bold
else if (description[i..].StartsWith("<b"))
{
AppendText(textBlock, description[last..i]);
int length = description[(i + BoldTagLeftLength)..].IndexOf('<');
AppendBoldText(textBlock, description.Slice(i + BoldTagLeftLength, length));
i += length + BoldTagFullLength;
last = i;
}
else
{
i += 1;
}
if (i == description.Length - 1)
{
AppendText(textBlock, description[last..(i + 1)]);
}
}
}
private static void AppendText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run { Text = slice.ToString() });
}
private static void AppendColorText(TextBlock text, in ReadOnlySpan<char> slice, Rgba32 color)
{
Color targetColor;
if (ThemeHelper.IsDarkMode(text.ActualTheme))
{
targetColor = color;
}
else
{
// Make lighter in light mode
Hsl32 hsl = color.ToHsl();
hsl.L *= 0.3;
targetColor = Rgba32.FromHsl(hsl);
}
text.Inlines.Add(new Run
{
Text = slice.ToString(),
Foreground = new SolidColorBrush(targetColor),
});
}
private static void AppendBoldText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run
{
Text = slice.ToString(),
FontWeight = FontWeights.Bold,
});
}
private static void AppendItalicText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run
{
Text = slice.ToString(),
FontStyle = Windows.UI.Text.FontStyle.Italic,
});
}
private static void AppendLineBreak(TextBlock text)
{
text.Inlines.Add(new LineBreak());
}
private void OnActualThemeChanged(FrameworkElement sender, object args)
{
// Simply re-apply texts
UpdateDescription((TextBlock)Content, Description);
}
}

View File

@@ -1,4 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shch="using:Snap.Hutao.Control.Helper">
<FontFamily x:Key="MiSans">ms-appx:///Resource/Font/MiSans-Regular.ttf#MiSans</FontFamily>
<FontFamily x:Key="CascadiaMonoAndMiSans">ms-appx:///Resource/Font/CascadiaMono.ttf#Cascadia Mono, ms-appx:///Resource/Font/MiSans-Regular.ttf#MiSans</FontFamily>
@@ -99,6 +102,7 @@
</Style>
<!-- TODO: When will DefaultInfoBarStyle added -->
<Style TargetType="InfoBar">
<Setter Property="shch:InfoBarHelper.IsTextSelectionEnabled" Value="False"/>
<Setter Property="FontFamily" Value="{StaticResource MiSans}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="CloseButtonStyle" Value="{StaticResource InfoBarCloseButtonStyle}"/>
@@ -181,6 +185,7 @@
Foreground="{ThemeResource InfoBarTitleForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarTitleHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarTitleVerticalOrientationMargin}"
IsTextSelectionEnabled="{TemplateBinding shch:InfoBarHelper.IsTextSelectionEnabled}"
Text="{TemplateBinding Title}"
TextWrapping="WrapWholeWords"/>
<TextBlock
@@ -190,6 +195,7 @@
Foreground="{ThemeResource InfoBarMessageForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarMessageHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarMessageVerticalOrientationMargin}"
IsTextSelectionEnabled="{TemplateBinding shch:InfoBarHelper.IsTextSelectionEnabled}"
Text="{TemplateBinding Message}"
TextWrapping="WrapWholeWords"/>
<ContentPresenter

View File

@@ -1,24 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 指示此方法为命令的调用方法
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class CommandAttribute : Attribute
{
/// <summary>
/// 指示此方法为命令的调用方法
/// </summary>
/// <param name="name">命令名称</param>
public CommandAttribute(string name)
{
}
/// <summary>
/// 是否允许并行执行
/// </summary>
public bool AllowConcurrentExecutions { get; set; }
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 指示此类自动生成构造器
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class ConstructorGeneratedAttribute : Attribute
{
/// <summary>
/// 指示此类自动生成构造器
/// </summary>
public ConstructorGeneratedAttribute()
{
}
/// <summary>
/// 是否调用基类构造函数
/// </summary>
public bool CallBaseConstructor { get; set; }
/// <summary>
/// 在构造函数中插入 HttpClient
/// </summary>
public bool ResolveHttpClient { get; set; }
}

View File

@@ -1,24 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class DependencyPropertyAttribute : Attribute
{
public DependencyPropertyAttribute(string name, Type type)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue, string valueChangedCallbackName)
{
}
public bool IsAttached { get; set; }
public Type AttachedType { get; set; } = default!;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Diagnostics;
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 高质量代码
/// </summary>
[AttributeUsage(AttributeTargets.All, Inherited = false)]
[Conditional("DEBUG")]
internal sealed class HighQualityAttribute : Attribute
{
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// 指示被标注的类型可注入 HttpClient
/// 由源生成器生成注入代码
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class HttpClientAttribute : Attribute
{
/// <summary>
/// 构造一个新的特性
/// </summary>
/// <param name="configuration">配置</param>
public HttpClientAttribute(HttpClientConfiguration configuration)
{
}
/// <summary>
/// 构造一个新的特性
/// </summary>
/// <param name="configuration">配置</param>
/// <param name="interfaceType">实现的接口类型</param>
public HttpClientAttribute(HttpClientConfiguration configuration, Type interfaceType)
{
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// Http客户端配置
/// </summary>
[HighQuality]
internal enum HttpClientConfiguration
{
/// <summary>
/// 默认配置
/// </summary>
Default,
/// <summary>
/// 米游社请求配置
/// </summary>
XRpc,
/// <summary>
/// 米游社登录请求配置
/// </summary>
XRpc2,
/// <summary>
/// Hoyolab app
/// </summary>
XRpc3,
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// 配置首选Http消息处理器特性
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class PrimaryHttpMessageHandlerAttribute : Attribute
{
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.MaxConnectionsPerServer"/>
public int MaxConnectionsPerServer { get; set; }
/// <summary>
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.UseCookies"/>
/// </summary>
public bool UseCookies { get; set; }
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
/// <summary>
/// 注入方法
/// </summary>
[HighQuality]
internal enum InjectAs
{
/// <summary>
/// 指示应注册为单例对象
/// </summary>
Singleton,
/// <summary>
/// 指示应注册为短期对象
/// </summary>
Transient,
/// <summary>
/// 指示应注册为范围对象
/// </summary>
Scoped,
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
/// <summary>
/// 指示被标注的类型可注入
/// 由源生成器生成注入代码
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class InjectionAttribute : Attribute
{
/// <summary>
/// 指示该类将注入为不带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
public InjectionAttribute(InjectAs injectAs)
{
}
/// <summary>
/// 指示该类将注入为带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
/// <param name="interfaceType">实现的接口类型</param>
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
{
}
}

View File

@@ -44,7 +44,7 @@ internal static partial class IocHttpClientConfiguration
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgent);
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
}
@@ -60,7 +60,7 @@ internal static partial class IocHttpClientConfiguration
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-aigis", string.Empty);
client.DefaultRequestHeaders.Add("x-rpc-app_id", "bll8iq97cem8");
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "2");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
client.DefaultRequestHeaders.Add("x-rpc-game_biz", "bbs_cn");
@@ -77,7 +77,7 @@ internal static partial class IocHttpClientConfiguration
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgentOversea);
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersionOversea);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.OSVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
client.DefaultRequestHeaders.Add("x-rpc-language", "zh-cn");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.WinUI.Notifications;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.DailyNote;
@@ -270,10 +269,18 @@ internal sealed partial class Activation : IActivation
}
else
{
await serviceProvider
.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.LaunchGamePage>(INavigationAwaiter.Default, true)
.ConfigureAwait(false);
if (currentWindowReference.Window is MainWindow)
{
await serviceProvider
.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.LaunchGamePage>(INavigationAwaiter.Default, true)
.ConfigureAwait(false);
}
else
{
// We have a non-Main Window, just exit current process anyway
Process.GetCurrentProcess().Kill();
}
}
}
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
namespace Snap.Hutao.Core.LifeCycle;

View File

@@ -115,7 +115,7 @@ internal static class LocalSetting
return Get<Windows.Foundation.Rect>(key, defaultValue);
}
public static ApplicationDataCompositeValue Get(string key, ApplicationDataCompositeValue defaultValue)
public static ApplicationDataCompositeValue Get(string key, ApplicationDataCompositeValue defaultValue)
{
return Get<ApplicationDataCompositeValue>(key, defaultValue);
}

View File

@@ -11,20 +11,6 @@ namespace Snap.Hutao.Extension;
/// </summary>
internal static partial class EnumerableExtension
{
/// <summary>
/// 尝试添加物品
/// </summary>
/// <typeparam name="T">物品类型</typeparam>
/// <param name="collection">集合</param>
/// <param name="item">物品</param>
public static void AddIfNotContains<T>(this Collection<T> collection, T item)
{
if (!collection.Contains(item))
{
collection.Add(item);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this Collection<TSource>? source)
{
@@ -57,4 +43,17 @@ internal static partial class EnumerableExtension
return count;
}
public static int FirstIndexOf<T>(this Collection<T> collection, Func<T, bool> predicate)
{
for (int index = 0; index < collection.Count; index++)
{
if (predicate(collection[index]))
{
return index;
}
}
return -1;
}
}

View File

@@ -15,7 +15,7 @@ internal static partial class EnumerableExtension
public static bool IsNullOrEmpty<TKey, TValue>([NotNullWhen(false)] this Dictionary<TKey, TValue>? source)
where TKey : notnull
{
if (source is { Count: >0 })
if (source is { Count: > 0 })
{
return false;
}

View File

@@ -30,6 +30,35 @@ internal static partial class EnumerableExtension
return (double)sum / span.Length;
}
public static T? BinarySearch<T>(this List<T> list, Func<T, int> comparer)
where T : class
{
Span<T> span = CollectionsMarshal.AsSpan(list);
int left = 0;
int right = span.Length - 1;
while (left <= right)
{
int middle = (left + right) / 2;
ref T current = ref span[middle];
int compareResult = comparer(current);
if (compareResult == 0)
{
return current;
}
else if (compareResult < 0)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return default;
}
/// <summary>
/// 如果传入列表不为空则原路返回,
/// 如果传入列表为空返回一个空的列表

View File

@@ -26,13 +26,7 @@ internal sealed class SpiralAbyssEntry : ObservableObject,
/// <summary>
/// 计划Id
/// </summary>
public int ScheduleId { get; set; }
/// <summary>
/// 视图 中使用的计划 Id 字符串
/// </summary>
[NotMapped]
public string Schedule { get => SH.ModelEntitySpiralAbyssScheduleFormat.Format(ScheduleId); }
public uint ScheduleId { get; set; }
/// <summary>
/// Uid
@@ -59,14 +53,4 @@ internal sealed class SpiralAbyssEntry : ObservableObject,
SpiralAbyss = spiralAbyss,
};
}
/// <summary>
/// 更新深渊信息
/// </summary>
/// <param name="spiralAbyss">深渊信息</param>
public void UpdateSpiralAbyss(Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss spiralAbyss)
{
SpiralAbyss = spiralAbyss;
OnPropertyChanged(nameof(SpiralAbyss));
}
}

View File

@@ -50,4 +50,9 @@ internal sealed class Achievement
/// 图标
/// </summary>
public string? Icon { get; set; }
/// <summary>
/// 版本
/// </summary>
public string Version { get; set; } = default!;
}

View File

@@ -34,6 +34,11 @@ internal sealed class Monster
/// </summary>
public string MonsterName { get; set; } = default!;
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = default!;
/// <summary>
/// 标题
/// </summary>

View File

@@ -0,0 +1,26 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata;
internal static class MonsterRelationship
{
public static MonsterRelationshipId Normalize(in MonsterRelationshipId id)
{
return (uint)id switch
{
5020U => 502U, // 幻形豕兽 · 水
5021U => 502U, // 幻形豕兽 · 水 (强化)
5040U => 504U, // 幻形蟹 · 水
5041U => 504U, // 幻形蟹 · 水 (强化)
5070U => 507U, // 幻形花鼠 · 水
5071U => 507U, // 幻形花鼠 · 水 (强化)
60402U => 60401U, // (火)岩龙蜥
60403U => 60401U, // (冰)岩龙蜥
60404U => 60401U, // (雷)岩龙蜥
_ => id,
};
}
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Metadata.Tower;
[Localization]
internal enum GoalType
{
[LocalizationKey(nameof(SH.ModelMetadataTowerGoalTypeDefeatMonsters))]
DefeatMonsters,
[LocalizationKey(nameof(SH.ModelMetadataTowerGoalTypeDefendTarget))]
DefendTarget,
}

View File

@@ -31,7 +31,7 @@ internal sealed class TowerFloor
public string Background { get; set; } = default!;
/// <summary>
/// 描述
/// 地脉紊乱
/// </summary>
public List<string> Descriptions { get; set; } = default!;
}

View File

@@ -35,8 +35,28 @@ internal sealed class TowerLevel
/// </summary>
public List<MonsterRelationshipId> FirstMonsters { get; set; } = default!;
/// <summary>
/// 上半怪物波次
/// </summary>
public List<TowerWave> FirstWaves { get; set; } = default!;
/// <summary>
/// 上半造物
/// </summary>
public NameDescription? FirstGadget { get; set; }
/// <summary>
/// 下半怪物预览
/// </summary>
public List<MonsterRelationshipId> SecondMonsters { get; set; } = default!;
public List<MonsterRelationshipId>? SecondMonsters { get; set; }
/// <summary>
/// 下半怪物波次
/// </summary>
public List<TowerWave> SecondWaves { get; set; } = default!;
/// <summary>
/// 下半造物
/// </summary>
public NameDescription? SecondGadget { get; set; }
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Tower;
internal sealed class TowerMonster
{
/// <summary>
/// 怪物关系Id
/// </summary>
public MonsterRelationshipId Id { get; set; }
/// <summary>
/// 个数
/// </summary>
public uint Count { get; set; }
/// <summary>
/// 是否攻击镇石
/// </summary>
public bool AttackMonolith { get; set; }
/// <summary>
/// 特殊词条
/// </summary>
public List<NameDescription>? Affixes { get; set; }
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Metadata.Tower;
internal sealed class TowerWave
{
/// <summary>
/// 波次类型
/// </summary>
public WaveType Type { get; set; }
/// <summary>
/// 额外描述
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 分波怪物
/// </summary>
public List<TowerMonster> Monsters { get; set; } = default!;
}

View File

@@ -0,0 +1,85 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Metadata.Tower;
/// <summary>
/// 第二波:击败所有怪物,下一波才会出现
/// D组不同的组同时在场各自分波独立
/// D组第一波不同的组同时在场各自分波独立
/// </summary>
[Localization]
internal enum WaveType
{
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeIndependent))]
Independent = 0,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave1))]
Wave1 = 1,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave2))]
Wave2 = 2,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave3))]
Wave3 = 3,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave4))]
Wave4 = 4,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupA))]
GroupA = 10,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupAWave1))]
GroupAWave1 = 11,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupAWave2))]
GroupAWave2 = 12,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupAWave3))]
GroupAWave3 = 13,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupB))]
GroupB = 20,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupBWave1))]
GroupBWave1 = 21,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupBWave2))]
GroupBWave2 = 22,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupBWave3))]
GroupBWave3 = 23,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupC))]
GroupC = 30,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupCWave1))]
GroupCWave1 = 31,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupCWave2))]
GroupCWave2 = 32,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupCWave3))]
GroupCWave3 = 33,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupD))]
GroupD = 40,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupDWave1))]
GroupDWave1 = 41,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupDWave2))]
GroupDWave2 = 42,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeGroupDWave3))]
GroupDWave3 = 43,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeSuppressed))]
Suppressed = 99,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeAdditional))]
Additional = 999,
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave1Additional))]
Wave1Additional = 1999,
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.ViewModel.AvatarProperty;
namespace Snap.Hutao.Model;
/// <summary>
/// 名称与描述
@@ -28,7 +28,10 @@ internal class NameDescription
Description = description;
}
public static NameDescription Default => DefaultValue;
public static NameDescription Default
{
get => DefaultValue;
}
/// <summary>
/// 名称

View File

@@ -7,5 +7,8 @@ internal sealed class NameValueDefaults
{
private static readonly NameValue<string> StringValue = new(SH.ModelNameValueDefaultName, SH.ModelNameValueDefaultDescription);
public static NameValue<string> String => StringValue;
public static NameValue<string> String
{
get => StringValue;
}
}

View File

@@ -439,7 +439,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 刷新于 {0:yyyy/MM/dd HH:mm:ss} 的本地化字符串。
/// 查找类似 刷新于 {0:yyyy.MM.dd HH:mm:ss} 的本地化字符串。
/// </summary>
internal static string ModelEntityDailyNoteRefreshTimeFormat {
get {
@@ -861,6 +861,249 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 击败怪物 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerGoalTypeDefeatMonsters {
get {
return ResourceManager.GetString("ModelMetadataTowerGoalTypeDefeatMonsters", resourceCulture);
}
}
/// <summary>
/// 查找类似 守护目标 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerGoalTypeDefendTarget {
get {
return ResourceManager.GetString("ModelMetadataTowerGoalTypeDefendTarget", resourceCulture);
}
}
/// <summary>
/// 查找类似 附加:增援怪物 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeAdditional {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeAdditional", resourceCulture);
}
}
/// <summary>
/// 查找类似 本间怪物 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeDefault {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeDefault", resourceCulture);
}
}
/// <summary>
/// 查找类似 A组不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupA {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupA", resourceCulture);
}
}
/// <summary>
/// 查找类似 A组第一波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupAWave1 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupAWave1", resourceCulture);
}
}
/// <summary>
/// 查找类似 A组第二波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupAWave2 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupAWave2", resourceCulture);
}
}
/// <summary>
/// 查找类似 A组第三波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupAWave3 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupAWave3", resourceCulture);
}
}
/// <summary>
/// 查找类似 B组不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupB {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupB", resourceCulture);
}
}
/// <summary>
/// 查找类似 B组第一波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupBWave1 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupBWave1", resourceCulture);
}
}
/// <summary>
/// 查找类似 B组第二波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupBWave2 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupBWave2", resourceCulture);
}
}
/// <summary>
/// 查找类似 B组第三波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupBWave3 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupBWave3", resourceCulture);
}
}
/// <summary>
/// 查找类似 C组不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupC {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupC", resourceCulture);
}
}
/// <summary>
/// 查找类似 C组第一波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupCWave1 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupCWave1", resourceCulture);
}
}
/// <summary>
/// 查找类似 C组第二波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupCWave2 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupCWave2", resourceCulture);
}
}
/// <summary>
/// 查找类似 C组第三波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupCWave3 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupCWave3", resourceCulture);
}
}
/// <summary>
/// 查找类似 D组不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupD {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupD", resourceCulture);
}
}
/// <summary>
/// 查找类似 D组第一波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupDWave1 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupDWave1", resourceCulture);
}
}
/// <summary>
/// 查找类似 D组第二波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupDWave2 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupDWave2", resourceCulture);
}
}
/// <summary>
/// 查找类似 D组第三波不同的组同时在场各自分波独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeGroupDWave3 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeGroupDWave3", resourceCulture);
}
}
/// <summary>
/// 查找类似 与其他怪物独立 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeIndependent {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeIndependent", resourceCulture);
}
}
/// <summary>
/// 查找类似 暂时没有分波信息 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeSuppressed {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeSuppressed", resourceCulture);
}
}
/// <summary>
/// 查找类似 第一波:击败所有怪物,下一波才会出现 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeWave1 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeWave1", resourceCulture);
}
}
/// <summary>
/// 查找类似 第一波附加:增援第一波怪物 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeWave1Additional {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeWave1Additional", resourceCulture);
}
}
/// <summary>
/// 查找类似 第二波:击败所有怪物,下一波才会出现 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeWave2 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeWave2", resourceCulture);
}
}
/// <summary>
/// 查找类似 第三波:击败所有怪物,下一波才会出现 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeWave3 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeWave3", resourceCulture);
}
}
/// <summary>
/// 查找类似 第四波:击败所有怪物,下一波才会出现 的本地化字符串。
/// </summary>
internal static string ModelMetadataTowerWaveTypeWave4 {
get {
return ResourceManager.GetString("ModelMetadataTowerWaveTypeWave4", resourceCulture);
}
}
/// <summary>
/// 查找类似 请更新角色橱窗数据 的本地化字符串。
/// </summary>
@@ -1744,7 +1987,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 找不到游戏配置文件 {0} 的本地化字符串。
/// 查找类似 无法读取游戏配置文件 {0},可能是文件不存在 的本地化字符串。
/// </summary>
internal static string ServiceGameSetMultiChannelConfigFileNotFound {
get {
@@ -1762,7 +2005,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成 的本地化字符串。
/// 查找类似 在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成,请重试 的本地化字符串。
/// </summary>
internal static string ServiceGameUnlockerFindModuleNoModuleFound {
get {
@@ -1771,7 +2014,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 在查找必要的模块时遇到问题:查找模块超时 的本地化字符串。
/// 查找类似 在查找必要的模块时遇到问题:查找模块超时,请重试 的本地化字符串。
/// </summary>
internal static string ServiceGameUnlockerFindModuleTimeLimitExeeded {
get {
@@ -1807,7 +2050,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 祈愿记录上传服务有效期至\n{0:yyyy-MM-dd HH:mm:ss} 的本地化字符串。
/// 查找类似 祈愿记录上传服务有效期至\n{0:yyyy.MM.dd HH:mm:ss} 的本地化字符串。
/// </summary>
internal static string ServiceHutaoUserGachaLogExpiredAt {
get {
@@ -3418,7 +3661,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 无法读取游戏配置文件: {0} 的本地化字符串。
/// 查找类似 无法读取游戏配置文件: {0},可能是文件不存在或权限不足 的本地化字符串。
/// </summary>
internal static string ViewModelLaunchGameMultiChannelReadFail {
get {
@@ -3679,7 +3922,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 搜索成就名称,描述或编号 的本地化字符串。
/// 查找类似 搜索成就名称,描述,版本或编号 的本地化字符串。
/// </summary>
internal static string ViewPageAchievementSearchPlaceholder {
get {
@@ -5721,6 +5964,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 评价软件 的本地化字符串。
/// </summary>
internal static string ViewPageSettingStoreReviewNavigate {
get {
return ResourceManager.GetString("ViewPageSettingStoreReviewNavigate", resourceCulture);
}
}
/// <summary>
/// 查找类似 贡献翻译 的本地化字符串。
/// </summary>
@@ -6000,6 +6252,24 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssAvatarAppearanceRankDescription {
get {
return ResourceManager.GetString("ViewSpiralAbyssAvatarAppearanceRankDescription", resourceCulture);
}
}
/// <summary>
/// 查找类似 角色使用率 = 本层上阵该角色次数(层内重复出现只记一次)/ 持有该角色的深渊记录总数 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssAvatarUsageRankDescription {
get {
return ResourceManager.GetString("ViewSpiralAbyssAvatarUsageRankDescription", resourceCulture);
}
}
/// <summary>
/// 查找类似 战斗数据 的本地化字符串。
/// </summary>
@@ -6046,7 +6316,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 详细数据 的本地化字符串。
/// 查找类似 分期详情 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssDetail {
get {
@@ -6064,7 +6334,7 @@ namespace Snap.Hutao.Resource.Localization {
}
/// <summary>
/// 查找类似 深渊记录 的本地化字符串。
/// 查找类似 深境螺旋 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssHeader {
get {
@@ -6072,6 +6342,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 本期统计 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssHutaoStatistics {
get {
return ResourceManager.GetString("ViewSpiralAbyssHutaoStatistics", resourceCulture);
}
}
/// <summary>
/// 查找类似 最深抵达 的本地化字符串。
/// </summary>
@@ -6090,6 +6369,24 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 上场角色 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssRecordBattleAvatars {
get {
return ResourceManager.GetString("ViewSpiralAbyssRecordBattleAvatars", resourceCulture);
}
}
/// <summary>
/// 查找类似 攻击地脉镇石 的本地化字符串。
/// </summary>
internal static string ViewSpiralAbyssRecordMonsterAttacksMonolith {
get {
return ResourceManager.GetString("ViewSpiralAbyssRecordMonsterAttacksMonolith", resourceCulture);
}
}
/// <summary>
/// 查找类似 刷新数据 的本地化字符串。
/// </summary>
@@ -6243,6 +6540,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 文档 的本地化字符串。
/// </summary>
internal static string ViewUserDocumentationHeader {
get {
return ResourceManager.GetString("ViewUserDocumentationHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 刷新 CookieToken 成功 的本地化字符串。
/// </summary>

View File

@@ -244,7 +244,7 @@
<value>Not refreshed</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>Refresh at {0:yyyy/MM/dd HH:mm:ss}</value>
<value>Refresh at {0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>Schedule {0}</value>
@@ -413,6 +413,87 @@
<value>Weapon Enhancement Materials</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
<value>Eliminate Monsters</value>
</data>
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
<value>Protect Ley Line Monolith</value>
</data>
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
<value>Addition: Monster Reinforce</value>
</data>
<data name="ModelMetadataTowerWaveTypeDefault" xml:space="preserve">
<value>Monsters in this Chamber</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
<value>Group A: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave1" xml:space="preserve">
<value>Group A Wave 1: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave2" xml:space="preserve">
<value>Group A Wave 2: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave3" xml:space="preserve">
<value>Group A Wave 3: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupB" xml:space="preserve">
<value>Group B: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave1" xml:space="preserve">
<value>Group B Wave 1: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave2" xml:space="preserve">
<value>Group B Wave 2: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave3" xml:space="preserve">
<value>Group B Wave 3: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupC" xml:space="preserve">
<value>Group C: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave1" xml:space="preserve">
<value>Group C Wave 1: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave2" xml:space="preserve">
<value>Group C Wave 2: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave3" xml:space="preserve">
<value>Group C Wave 3: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupD" xml:space="preserve">
<value>Group D: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave1" xml:space="preserve">
<value>Group D Wave 1: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave2" xml:space="preserve">
<value>Group D Wave 2: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave3" xml:space="preserve">
<value>Group D Wave 3: Different groups coexist and have independent waves</value>
</data>
<data name="ModelMetadataTowerWaveTypeIndependent" xml:space="preserve">
<value>Independent from other monsters</value>
</data>
<data name="ModelMetadataTowerWaveTypeSuppressed" xml:space="preserve">
<value>No wave data</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1" xml:space="preserve">
<value>Wave 1: A wave will spawn only after killing all enemies in the previous wave</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
<value>Wave 1 Addition: First wave of monster reinforce</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
<value>Wave 2: A wave will spawn only after killing all enemies in the previous wave</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave3" xml:space="preserve">
<value>Wave 3: A wave will spawn only after killing all enemies in the previous wave</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
<value>Wave 4: A wave will spawn only after killing all enemies in the previous wave</value>
</data>
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
<value>Please update showcase data</value>
</data>
@@ -735,16 +816,16 @@
<value>PowerShell installation directory not found</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>Game configuration file {0} not found</value>
<value>Unable to read game config file {0}, file may be not exist</value>
</data>
<data name="ServiceGameSetMultiChannelUnauthorizedAccess" xml:space="preserve">
<value>Unable to read or save profile, please try again in administrator mode</value>
</data>
<data name="ServiceGameUnlockerFindModuleNoModuleFound" xml:space="preserve">
<value>Error finding required modules: could not read any module, the protection driver may have been loaded</value>
<value>Error finding required modules: could not read any module, the protection driver may have been loaded; please retry</value>
</data>
<data name="ServiceGameUnlockerFindModuleTimeLimitExeeded" xml:space="preserve">
<value>Error finding required modules: timeout</value>
<value>Error finding required modules: timeout; please retry</value>
</data>
<data name="ServiceGameUnlockerInterestedPatternNotFound" xml:space="preserve">
<value>Error matching memory pattern: no expected content</value>
@@ -756,7 +837,7 @@
<value>Error reading process modules' memory: could not read valid value in given address</value>
</data>
<data name="ServiceHutaoUserGachaLogExpiredAt" xml:space="preserve">
<value>Wish history data backup service will be available until\n{0:yyyy-MM-dd HH:mm:ss}</value>
<value>Wish history data backup service will expire at \n{0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ServiceMetadataFileNotFound" xml:space="preserve">
<value>Unable to find cached metadata file</value>
@@ -1293,7 +1374,7 @@
<value>Convert server failed</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>Unable to read game client configuration: {0}</value>
<value>Unable to read game config file: {0}, file may be not exist not lack of user permission</value>
</data>
<data name="ViewModelLaunchGamePathInvalid" xml:space="preserve">
<value>Game program path is incorrect. Change it in the Settings Page.</value>
@@ -1380,7 +1461,7 @@
<value>Delete Current Archive</value>
</data>
<data name="ViewPageAchievementSearchPlaceholder" xml:space="preserve">
<value>Search achievement name, description or ID</value>
<value>Name, description, version or ID</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>Prefer incomplete</value>
@@ -2013,7 +2094,7 @@
<value>Enable Advanced Features</value>
</data>
<data name="ViewPageSettingOfficialSiteNavigate" xml:space="preserve">
<value>Go to Official Website</value>
<value>Official Website</value>
</data>
<data name="ViewPageSettingResetAction" xml:space="preserve">
<value>Reset</value>
@@ -2049,7 +2130,7 @@
<value>Shell Experience</value>
</data>
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
<value>Sponsor Us</value>
<value>Sponsor Snap Hutao</value>
</data>
<data name="ViewPageSettingStorageHeader" xml:space="preserve">
<value>Storage</value>
@@ -2060,11 +2141,14 @@
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
<value>Set</value>
</data>
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>Rate Snap Hutao</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>Contribute Translations</value>
</data>
<data name="ViewPageSettingUpdateCheckAction" xml:space="preserve">
<value>Go to Store</value>
<value>Store Page</value>
</data>
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
<value>Webview2 Runtime</value>
@@ -2153,6 +2237,12 @@
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>Sign in or register now</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<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 name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
<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 name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>Battle Statistics</value>
</data>
@@ -2169,13 +2259,16 @@
<value>Most Defeats</value>
</data>
<data name="ViewSpiralAbyssDetail" xml:space="preserve">
<value>Details</value>
<value>Schedules Detail</value>
</data>
<data name="ViewSpiralAbyssEnergySkill" xml:space="preserve">
<value>Elemental Bursts Unleashed</value>
</data>
<data name="ViewSpiralAbyssHeader" xml:space="preserve">
<value>Abyss Records</value>
<value>Spiral Abyss</value>
</data>
<data name="ViewSpiralAbyssHutaoStatistics" xml:space="preserve">
<value>Statistics</value>
</data>
<data name="ViewSpiralAbyssMaxFloor" xml:space="preserve">
<value>Deepest Descent</value>
@@ -2183,6 +2276,12 @@
<data name="ViewSpiralAbyssNormalSkill" xml:space="preserve">
<value>Elemental Skills Cast</value>
</data>
<data name="ViewSpiralAbyssRecordBattleAvatars" xml:space="preserve">
<value>Lineup</value>
</data>
<data name="ViewSpiralAbyssRecordMonsterAttacksMonolith" xml:space="preserve">
<value>Attack monolith</value>
</data>
<data name="ViewSpiralAbyssRefresh" xml:space="preserve">
<value>Refresh Data</value>
</data>
@@ -2234,6 +2333,9 @@
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>Please login first</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>Document</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>Refresh CookieToken successfully</value>
</data>

View File

@@ -172,10 +172,10 @@
<value>ゲームスタート</value>
</data>
<data name="CoreScheduleTaskHelperDailyNoteRefreshTaskDescription" xml:space="preserve">
<value>胡桃实时便笺刷新任务 | 请勿编辑或删除。</value>
<value>胡桃がリアルタイムノートを更新しています | 編集や削除をしないでください</value>
</data>
<data name="CoreThreadingSemaphoreSlimDisposed" xml:space="preserve">
<value>信号量已经被释放,操作取消</value>
<value>セマフォが解放され、操作がキャンセルされました</value>
</data>
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
<value>WebView2 ランタイムが検出されませんでした</value>
@@ -226,7 +226,7 @@
<value>第 {0} 間</value>
</data>
<data name="ModelBindingHutaoTeamUpCountFormat" xml:space="preserve">
<value>上场 {0}</value>
<value>出場回数{0}</value>
</data>
<data name="ModelBindingLaunchGameLaunchSchemeBilibili" xml:space="preserve">
<value>世界樹サーバー</value>
@@ -244,7 +244,7 @@
<value>未更新</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>更新日時 {0:yyyy/MM/dd HH:mm:ss}</value>
<value>更新日時 {0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>第 {0} 期</value>
@@ -413,6 +413,87 @@
<value>武器強化素材</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
<value>击败怪物</value>
</data>
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
<value>守护目标</value>
</data>
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
<value>附加:增援怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeDefault" xml:space="preserve">
<value>本间怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
<value>A组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave1" xml:space="preserve">
<value>A组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave2" xml:space="preserve">
<value>A组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave3" xml:space="preserve">
<value>A组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupB" xml:space="preserve">
<value>B组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave1" xml:space="preserve">
<value>B组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave2" xml:space="preserve">
<value>B组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave3" xml:space="preserve">
<value>B组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupC" xml:space="preserve">
<value>C组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave1" xml:space="preserve">
<value>C组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave2" xml:space="preserve">
<value>C组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave3" xml:space="preserve">
<value>C组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupD" xml:space="preserve">
<value>D组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave1" xml:space="preserve">
<value>D组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave2" xml:space="preserve">
<value>D组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave3" xml:space="preserve">
<value>D组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeIndependent" xml:space="preserve">
<value>与其他怪物独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeSuppressed" xml:space="preserve">
<value>暂时没有分波信息</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1" xml:space="preserve">
<value>第一波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
<value>第一波附加:增援第一波怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
<value>第二波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave3" xml:space="preserve">
<value>第三波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
<value>第四波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
<value>キャラクターラインナップを更新する</value>
</data>
@@ -429,7 +510,7 @@
<value>{0} つのアチーブメントを追加 | {1} つのアチーブメントを更新 |{2} つのアチーブメントを削除</value>
</data>
<data name="ServiceAchievementUserdataCorruptedInnerIdNotUnique" xml:space="preserve">
<value>单个成就存档内发现多个相同的成就 Id</value>
<value>複数の同一アチーブメント Idがアーカイブに混在しています</value>
</data>
<data name="ServiceAvatarInfoPropertyAtk" xml:space="preserve">
<value>攻撃力</value>
@@ -558,10 +639,10 @@
<value>キャラクターラインナップ:{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>保存养成计划状态失败</value>
<value>育成計画のステータスを保存できません</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted2" xml:space="preserve">
<value>存在多个选中的养成计划</value>
<value>育成計画が複数セレクトしています</value>
</data>
<data name="ServiceDailyNoteNotifierActionLaunchGameButton" xml:space="preserve">
<value>スタート</value>
@@ -603,7 +684,7 @@
<value>現在の天然樹脂:{0}</value>
</data>
<data name="ServiceDailyNoteNotifierTitle" xml:space="preserve">
<value>实时便笺提醒</value>
<value>リアルタイムノート通知</value>
</data>
<data name="ServiceDailyNoteNotifierTransformer" xml:space="preserve">
<value>参量物質変化器</value>
@@ -618,7 +699,7 @@
<value>{0}:祈願履歴を確認できません</value>
</data>
<data name="ServiceGachaLogEndIdUserdataCorruptedMessage" xml:space="preserve">
<value>无法获取祈愿记录 End Id</value>
<value>祈願履歴を確認できません End Id</value>
</data>
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
<value>イベント祈願・キャラクター</value>
@@ -636,16 +717,16 @@
<value>祈願履歴のアップロードサービスが利用できません</value>
</data>
<data name="ServiceGachaLogUIGFImportItemInvalidFormat" xml:space="preserve">
<value>数据包含异常物品, Id{0}</value>
<value>無効なアイテムが含まれてます、Id{0}</value>
</data>
<data name="ServiceGachaLogUrlProviderAuthkeyRequestFailed" xml:space="preserve">
<value>请求验证密钥失败</value>
</data>
<data name="ServiceGachaLogUrlProviderCachePathInvalid" xml:space="preserve">
<value>未正确提供原神路径,或当前设置的路径不正确</value>
<value>原神のパスの書き方に誤りがあるか、またはパスを正しく設定されていません。</value>
</data>
<data name="ServiceGachaLogUrlProviderCachePathNotFound" xml:space="preserve">
<value>找不到原神内置浏览器缓存路径\n{0}</value>
<value>原神ゲーム内ブラウザのキャッシュの保存場所が見つかりません\n{0}</value>
</data>
<data name="ServiceGachaLogUrlProviderCacheUrlNotFound" xml:space="preserve">
<value>利用可能なUrlが見つかりません</value>
@@ -657,31 +738,31 @@
<value>HoYoLabユーザーのSToken 更新はサポートしていません。</value>
</data>
<data name="ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale" xml:space="preserve">
<value>Url 中的语言{0} 胡桃的语言:{1} 不匹配,请切换到对应语言重试</value>
<value>Url の言語{0} 胡桃の設定言語:{1} とマッチングしません。言語を切り替えて再度試してください</value>
</data>
<data name="ServiceGachaStatisticsFactoryItemIdInvalid" xml:space="preserve">
<value>Item Id{0} はサポートしていません</value>
</data>
<data name="ServiceGachaUIGFImportLanguageNotMatch" xml:space="preserve">
<value>UIGF 文件的语言{0} 胡桃的语言:{1} 不匹配,请切换到对应语言重试</value>
<value>UIGF ファイルの言語{0} 胡桃の設定言語:{1} とマッチングしません。言語を切り替えて再度試してください</value>
</data>
<data name="ServiceGameDetectGameAccountMultiMatched" xml:space="preserve">
<value>存在多个匹配账号,请删除重复的账号</value>
</data>
<data name="ServiceGameEnsureGameResourceQueryResourceInformation" xml:space="preserve">
<value>查询游戏资源信息</value>
<value>ゲームのリソース情報を確認</value>
</data>
<data name="ServiceGameFileOperationExceptionMessage" xml:space="preserve">
<value>游戏文件操作失败:{0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>游戏进程已退出</value>
<value>ゲームプロセスが終了した</value>
</data>
<data name="ServiceGameLaunchPhaseProcessInitializing" xml:space="preserve">
<value>正在初始化游戏进程</value>
<value>ゲームプロセスが初期化している</value>
</data>
<data name="ServiceGameLaunchPhaseProcessStarted" xml:space="preserve">
<value>游戏进程已启动</value>
<value>ゲームプロセスが生成された</value>
</data>
<data name="ServiceGameLaunchPhaseUnlockFpsFailed" xml:space="preserve">
<value>FPS上限解除失敗、プロセスが終了させる</value>
@@ -693,7 +774,7 @@
<value>FPS上限解除を試みる</value>
</data>
<data name="ServiceGameLaunchPhaseWaitingProcessExit" xml:space="preserve">
<value>等待游戏进程退出</value>
<value>プロセスが終了するまで待機中</value>
</data>
<data name="ServiceGameLocatorFileOpenPickerCommitText" xml:space="preserve">
<value>ゲーム本体を選択する</value>
@@ -726,7 +807,7 @@
<value>下载客户端文件失败:{0}</value>
</data>
<data name="ServiceGamePathLocateFailed" xml:space="preserve">
<value>无法找到游戏路径,请前往设置修改</value>
<value>ゲームパスが見つかりません、設定にて変更してください</value>
</data>
<data name="ServiceGameRegisteryInteropLongPathsDisabled" xml:space="preserve">
<value>未开启长路径功能,无法设置注册表键值</value>
@@ -735,16 +816,16 @@
<value>PowerShellのインストールディレクトリが見つかりません</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>找不到游戏配置文件 {0}</value>
<value>无法读取游戏配置文件 {0},可能是文件不存在</value>
</data>
<data name="ServiceGameSetMultiChannelUnauthorizedAccess" xml:space="preserve">
<value>設定ファイルを読み取れない、または保存できませんでした。管理者モードで再試行してください。</value>
</data>
<data name="ServiceGameUnlockerFindModuleNoModuleFound" xml:space="preserve">
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成</value>
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成,请重试</value>
</data>
<data name="ServiceGameUnlockerFindModuleTimeLimitExeeded" xml:space="preserve">
<value>必要なモジュールを検索する際にエラーが発生しました:検索タイムアウト</value>
<value>在查找必要的模块时遇到问题:查找模块超时,请重试</value>
</data>
<data name="ServiceGameUnlockerInterestedPatternNotFound" xml:space="preserve">
<value>在匹配内存时遇到问题:无法匹配到期望的内容</value>
@@ -756,43 +837,43 @@
<value>在读取游戏进程内存时遇到问题:无法读取到指定地址的有效值</value>
</data>
<data name="ServiceHutaoUserGachaLogExpiredAt" xml:space="preserve">
<value>祈願履歴のアップロード期限は\n{0:yyyy-MM-dd HH:mm:ss}</value>
<value>祈願履歴のアップロード期限は\n{0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ServiceMetadataFileNotFound" xml:space="preserve">
<value>キャッシュされたメタデータファイルが見つかりませんでした</value>
</data>
<data name="ServiceMetadataNotInitialized" xml:space="preserve">
<value>元数据服务尚未初始化,或初始化失败</value>
<value>メタデータサービスが初期化されていないか、または初期化できませんでした</value>
</data>
<data name="ServiceMetadataParseFailed" xml:space="preserve">
<value>元数据校验文件解析失败</value>
<value>メタデータの検証ファイルを解析できなかった</value>
</data>
<data name="ServiceMetadataRequestFailed" xml:space="preserve">
<value>元数据校验文件下载失败</value>
<value>メタデータの検証ファイルをダウンロードできなかった</value>
</data>
<data name="ServiceMetadataVersionNotSupported" xml:space="preserve">
<value>胡桃のバージョンが古すぎるため、アップデートを推奨します。</value>
</data>
<data name="ServiceSignInClaimRewardFailedFormat" xml:space="preserve">
<value>签到失败,{0}</value>
<value>ログインボーナスを獲得できなかった、{0}</value>
</data>
<data name="ServiceSignInRewardListRequestFailed" xml:space="preserve">
<value>获取奖励列表失败</value>
</data>
<data name="ServiceSignInRiskVerificationFailed" xml:space="preserve">
<value>验证失败,请前往米游社原神签到页面自行领取奖励</value>
<value>認証に失敗した、MiYouSheの原神コーナーでログインボーナスを獲得してください</value>
</data>
<data name="ServiceSignInSuccessRewardFormat" xml:space="preserve">
<value>签到成功,{0}×{1}</value>
<value>ログインボーナスを獲得した、{0}×{1}</value>
</data>
<data name="ServiceUIGFImportUnsupportedVersion" xml:space="preserve">
<value>サポートされていないUIGFバージョン</value>
</data>
<data name="ServiceUserCurrentMultiMatched" xml:space="preserve">
<value>多个用户记录为选中状态</value>
<value>ユーザー情報が複数セレクトしています</value>
</data>
<data name="ServiceUserCurrentUpdateAndSaveFailed" xml:space="preserve">
<value>用户 {0} 状态保存失败</value>
<value>ユーザー {0} のステータスを保存できません</value>
</data>
<data name="ServiceUserProcessCookieNoMid" xml:space="preserve">
<value>入力した Cookie には Mid が必要です</value>
@@ -870,10 +951,10 @@
<value>予測</value>
</data>
<data name="ViewControlStatisticsSegmentedItemContentProportion" xml:space="preserve">
<value>比例</value>
<value>割合</value>
</data>
<data name="ViewControlStatisticsSegmentedItemContentStatistics" xml:space="preserve">
<value>统计</value>
<value>統計</value>
</data>
<data name="ViewCultivationHeader" xml:space="preserve">
<value>育成計画</value>
@@ -906,19 +987,19 @@
<value>アーカイブにアチーブメントをインポート</value>
</data>
<data name="ViewDialogCultivateBatchAvatarLevelTarget" xml:space="preserve">
<value>角色目标等级</value>
<value>キャラクター目標レベル</value>
</data>
<data name="ViewDialogCultivateBatchSkillATarget" xml:space="preserve">
<value>普通攻击目标等级</value>
<value>通常攻撃目標レベル</value>
</data>
<data name="ViewDialogCultivateBatchSkillETarget" xml:space="preserve">
<value>元素战技目标等级</value>
<value>元素スキル目標レベル</value>
</data>
<data name="ViewDialogCultivateBatchSkillQTarget" xml:space="preserve">
<value>元素爆发目标等级</value>
<value>元素爆発目標レベル</value>
</data>
<data name="ViewDialogCultivateBatchWeaponLevelTarget" xml:space="preserve">
<value>武器目标等级</value>
<value>武器目標レベル</value>
</data>
<data name="ViewDialogCultivateProjectAttachUid" xml:space="preserve">
<value>绑定当前用户与角色</value>
@@ -930,10 +1011,10 @@
<value>新規育成計画</value>
</data>
<data name="ViewDialogCultivatePromotionDeltaBatchTitle" xml:space="preserve">
<value>批量添加或更新到当前养成计划</value>
<value>現在の育成計画に一括追加または更新する</value>
</data>
<data name="ViewDialogCultivatePromotionDeltaTitle" xml:space="preserve">
<value>添加或更新到当前养成计划</value>
<value>現在の育成計画に追加または更新する</value>
</data>
<data name="ViewDialogDailyNoteNotificationDailyTaskNotify" xml:space="preserve">
<value>デイリー依頼まだ完了していません</value>
@@ -951,7 +1032,7 @@
<value>ホームページに表示</value>
</data>
<data name="ViewDialogDailyNoteNotificationTitle" xml:space="preserve">
<value>实时便笺通知设置</value>
<value>リアルタイムノートの通知設定</value>
</data>
<data name="ViewDialogDailyNoteNotificationTransformerNotify" xml:space="preserve">
<value>参量物質変化器は使えるようになりました</value>
@@ -981,19 +1062,19 @@
<value>接口需要返回形如上方所示的 Json 数据,多余的数据会被忽略</value>
</data>
<data name="ViewDialogGeetestCustomUrlReturnDataDescription2" xml:space="preserve">
<value>"code" 0 时,指示验证成功,其他的值均视为验证失败</value>
<value>"code" 0 の場合のみ認証成功です。他の戻り値は認証失敗となります。</value>
</data>
<data name="ViewDialogGeetestCustomUrlReturnDataHeader" xml:space="preserve">
<value>返回数据</value>
<value>結果を返す</value>
</data>
<data name="ViewDialogGeetestCustomUrlSampleDescription1" xml:space="preserve">
<value>{0} 将在实际请求时替换为 gt</value>
<value>{0} はリクエストの際、gtに切り替えます</value>
</data>
<data name="ViewDialogGeetestCustomUrlSampleDescription2" xml:space="preserve">
<value>{1} 将在实际请求时替换为 challenge</value>
<value>{1} はリクエストの際、challengeに切り替えます</value>
</data>
<data name="ViewDialogGeetestCustomUrlSampleDescription3" xml:space="preserve">
<value>将会通过 GET 方式对接口发送请求</value>
<value>GETメソッドでリクエストの処理を行います。</value>
</data>
<data name="ViewDialogGeetestCustomUrlSampleHeader" xml:space="preserve">
<value>例</value>
@@ -1038,7 +1119,7 @@
<value>ゲームランチャー切り替え中</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>该操作是不可逆的,所有用户登录状态会丢失</value>
<value>この操作は取り消せません。すべてのユーザーのログイン状態が解除されます。</value>
</data>
<data name="ViewDialogSettingDeleteUserDataTitle" xml:space="preserve">
<value>ユーザーデータを完全に削除しますか</value>
@@ -1062,19 +1143,19 @@
<value>祈願履歴</value>
</data>
<data name="ViewGuideStepAgreementIHaveReadText" xml:space="preserve">
<value>我已阅读并同意</value>
<value>規約を熟読し、それに同意します</value>
</data>
<data name="ViewGuideStepAgreementIssueReport" xml:space="preserve">
<value>フィードバックの書き方と流れ</value>
</data>
<data name="ViewGuideStepAgreementOpenSourceLicense" xml:space="preserve">
<value>Snap Hutao 开源许可</value>
<value>Snap Hutao オープンソースライセンス</value>
</data>
<data name="ViewGuideStepAgreementPrivacyPolicy" xml:space="preserve">
<value>用户数据与隐私权益</value>
<value>プライバシーポリシー</value>
</data>
<data name="ViewGuideStepAgreementTermOfService" xml:space="preserve">
<value>用户使用协议与法律声明</value>
<value>利用規約</value>
</data>
<data name="ViewGuideStepDocument" xml:space="preserve">
<value>ドキュメント</value>
@@ -1113,13 +1194,13 @@
<value>ゲームランチャー</value>
</data>
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
<value>存档 [{0}] 添加成功</value>
<value>アーカイブ [{0}] を作成されました</value>
</data>
<data name="ViewModelAchievementArchiveAlreadyExists" xml:space="preserve">
<value>不能添加名称重复的存档 [{0}]</value>
<value>アーカイブ [{0}] はすでに使用されています。別の名前で作成してください</value>
</data>
<data name="ViewModelAchievementArchiveInvalidName" xml:space="preserve">
<value>不能添加名称无效的存档</value>
<value>無効な文字が含むアーカイブを作成できません</value>
</data>
<data name="ViewModelAchievementExportFileType" xml:space="preserve">
<value>UIAF ファイル</value>
@@ -1131,13 +1212,13 @@
<value>UIAF バージョンが古いため、インポートできません</value>
</data>
<data name="ViewModelAchievementRemoveArchiveContent" xml:space="preserve">
<value>该操作是不可逆的,该存档和其内的所有成就状态会丢失</value>
<value>この操作は取り消せません。アーカイブおよびアチーブメントの達成ログが削除されます。</value>
</data>
<data name="ViewModelAchievementRemoveArchiveTitle" xml:space="preserve">
<value>确定要删除存档 {0} 吗</value>
<value>{0} を削除してもよろしいでしょうか</value>
</data>
<data name="ViewModelAvatarPropertyBatchCultivateProgressTitle" xml:space="preserve">
<value>获取培养材料中,请稍候...</value>
<value>素材リスト取得中、しばらくお待ちください</value>
</data>
<data name="ViewModelAvatarPropertyCalculateWeaponNull" xml:space="preserve">
<value>当前角色无法计算,请同步信息后再试</value>
@@ -1164,10 +1245,10 @@
<value>育成計画の追加に失敗しました</value>
</data>
<data name="ViewModelCultivationBatchAddCompletedFormat" xml:space="preserve">
<value>操作完成:添加/更新:{0} 个,跳过 {1}</value>
<value>完了した:追加/更新:{0}、スキップ{1}</value>
</data>
<data name="ViewModelCultivationBatchAddIncompletedFormat" xml:space="preserve">
<value>操作未全部完成:添加/更新:{0} 个,跳过 {1}</value>
<value>一部完了した:追加/更新:{0}、スキップ{1}</value>
</data>
<data name="ViewModelCultivationEntryAddSuccess" xml:space="preserve">
<value>現在の育成計画は正常に追加された</value>
@@ -1206,16 +1287,16 @@
<value>注册计划任务失败,请使用管理员模式重试</value>
</data>
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
<value>正在获取实时便笺信息,请稍候</value>
<value>リアルタイムノートの情報を取得中、しばらくお待ちください</value>
</data>
<data name="ViewModelExportSuccessMessage" xml:space="preserve">
<value>成功保存到指定位置</value>
<value>指定された位置に保存しました</value>
</data>
<data name="ViewModelExportSuccessTitle" xml:space="preserve">
<value>エクスポート成功しました</value>
</data>
<data name="ViewModelExportWarningMessage" xml:space="preserve">
<value>写入文件时遇到问题</value>
<value>書き込み処理でエラーが発生しました</value>
</data>
<data name="ViewModelExportWarningTitle" xml:space="preserve">
<value>エクスポート失敗</value>
@@ -1233,7 +1314,7 @@
<value>UIGF バージョンが古いため、インポートできません</value>
</data>
<data name="ViewModelGachaLogImportWarningMessage2" xml:space="preserve">
<value>导入数据中包含了不支持的物品</value>
<value>インポートデータにサポートされないアイテムが含まれている</value>
</data>
<data name="ViewModelGachaLogImportWarningTitle" xml:space="preserve">
<value>インポート失敗</value>
@@ -1263,7 +1344,7 @@
<value>胡桃クラウドにアップロード中</value>
</data>
<data name="ViewModelGuideActionAgreement" xml:space="preserve">
<value>我已阅读并同意上方的条款</value>
<value>上記の規約を熟読し、それに同意します</value>
</data>
<data name="ViewModelGuideActionComplete" xml:space="preserve">
<value>OK</value>
@@ -1293,7 +1374,7 @@
<value>サーバー切り替えできませんでした</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0}</value>
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
<data name="ViewModelLaunchGamePathInvalid" xml:space="preserve">
<value>指定されたパスにアクセスできません。設定で変更してください。</value>
@@ -1305,13 +1386,13 @@
<value>アカウントの切り替えができませんでした</value>
</data>
<data name="ViewModelSettingActionComplete" xml:space="preserve">
<value>操作完成</value>
<value>完了した</value>
</data>
<data name="ViewModelSettingClearWebCacheFail" xml:space="preserve">
<value>清除失败,文件目录权限不足,请使用管理员模式重试</value>
<value>削除に失敗しました。ディレクトリのアクセス許可がありません。「管理者として実行」で再度試してください</value>
</data>
<data name="ViewModelSettingClearWebCachePathInvalid" xml:space="preserve">
<value>清除失败,找不到目录{0}</value>
<value>削除に失敗しました。ディレクトリが見つかりませんでした{0}</value>
</data>
<data name="ViewModelSettingClearWebCacheSuccess" xml:space="preserve">
<value>消去しました</value>
@@ -1341,7 +1422,7 @@
<value>ユーザー [{0}] の Cookie が更新されました。</value>
</data>
<data name="ViewModelViewDisposedOperationCancel" xml:space="preserve">
<value>页面资源已经被释放,操作取消</value>
<value>ビューリソースが解放され、操作がキャンセルされました</value>
</data>
<data name="ViewModelWelcomeDownloadCompleteMessage" xml:space="preserve">
<value>胡桃を利用できるようになりました</value>
@@ -1377,10 +1458,10 @@
<value>インポート</value>
</data>
<data name="ViewPageAchievementRemoveArchive" xml:space="preserve">
<value>删除当前存档</value>
<value>このアーカイブを削除する</value>
</data>
<data name="ViewPageAchievementSearchPlaceholder" xml:space="preserve">
<value>アチーブメント、キャプションまたは番号で検索</value>
<value>アチーブメント、キャプション、バージョンまたは番号で検索</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>优先未完成</value>
@@ -1395,10 +1476,10 @@
<value>聖遺物スコア</value>
</data>
<data name="ViewPageAvatarPropertyCalculateAll" xml:space="preserve">
<value>所有角色与武器</value>
<value>すべてのキャラクターと武器</value>
</data>
<data name="ViewPageAvatarPropertyCalculateCurrent" xml:space="preserve">
<value>当前角色与武器</value>
<value>現在のキャラクターと武器</value>
</data>
<data name="ViewPageAvatarPropertyCritScore" xml:space="preserve">
<value>会心スコア</value>
@@ -1470,10 +1551,10 @@
<value>アイテム</value>
</data>
<data name="ViewPageCultivationMaterialList" xml:space="preserve">
<value>材料清单</value>
<value>素材リスト</value>
</data>
<data name="ViewPageCultivationMaterialStatistics" xml:space="preserve">
<value>材料统计</value>
<value>素材情報</value>
</data>
<data name="ViewPageCultivationNavigateAction" xml:space="preserve">
<value>前往</value>
@@ -1527,7 +1608,7 @@
<value>自動更新</value>
</data>
<data name="ViewPageDailyNoteSettingAutoRefreshDescription" xml:space="preserve">
<value>间隔选定的时间后刷新添加的实时便笺</value>
<value>指定間隔でリアルタイムノートの更新を設定する</value>
</data>
<data name="ViewPageDailyNoteSettingRefreshElevatedHint" xml:space="preserve">
<value>这些选项仅允许在非管理员模式下更改</value>
@@ -1563,16 +1644,16 @@
<value>クラウドサービスの購入/更新</value>
</data>
<data name="ViewPageGachaLogHutaoCloudDelete" xml:space="preserve">
<value>删除此 Uid 的云端存档</value>
<value>このUidのクラウドバックアップを削除する</value>
</data>
<data name="ViewPageGachaLogHutaoCloudDeveloperHint" xml:space="preserve">
<value>开发者账号无视服务到期时间</value>
<value>デベロッパーアカウントは利用期限ありません</value>
</data>
<data name="ViewPageGachaLogHutaoCloudNotAllowed" xml:space="preserve">
<value>胡桃云服务时长不足</value>
</data>
<data name="ViewPageGachaLogHutaoCloudRetrieve" xml:space="preserve">
<value>下载此 Uid 的云端存档</value>
<value>このUidのクラウドバックアップをダウンロードする</value>
</data>
<data name="ViewPageGachaLogHutaoCloudSpiralAbyssActivityDescription" xml:space="preserve">
<value>每期深渊首次上传可免费获得 3 天时长</value>
@@ -1581,7 +1662,7 @@
<value>螺旋の記録をアップロード</value>
</data>
<data name="ViewPageGachaLogHutaoCloudUpload" xml:space="preserve">
<value>上传当前的祈愿存档</value>
<value>現在の祈願履歴をアップロード</value>
</data>
<data name="ViewPageGachaLogImportAction" xml:space="preserve">
<value>インポート</value>
@@ -1605,7 +1686,7 @@
<value>Urlを入力する</value>
</data>
<data name="ViewPageGachaLogRefreshByManualInputDescription" xml:space="preserve">
<value>使用由你提供的 Url 刷新祈愿记录</value>
<value>旅人が用意したUrlで祈願履歴を更新</value>
</data>
<data name="ViewPageGachaLogRefreshBySToken" xml:space="preserve">
<value>SToken 更新</value>
@@ -1617,10 +1698,10 @@
<value>キャッシュの再読み込み</value>
</data>
<data name="ViewPageGachaLogRefreshByWebCacheDescription" xml:space="preserve">
<value>使用游戏内浏览器的网页缓存刷新祈愿记录</value>
<value>ゲーム内ブラウザのキャッシュで祈願履歴を更新</value>
</data>
<data name="ViewPageGachaLogRemoveArchiveAction" xml:space="preserve">
<value>删除当前存档</value>
<value>このアーカイブを削除する</value>
</data>
<data name="ViewPageGahcaLogPivotAvatar" xml:space="preserve">
<value>キャラクター</value>
@@ -1836,7 +1917,7 @@
<value>アカウントを検出</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountRemoveToolTip" xml:space="preserve">
<value>除</value>
<value>除</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountRenameToolTip" xml:space="preserve">
<value>リネーム</value>
@@ -1848,16 +1929,16 @@
<value>サーバー</value>
</data>
<data name="ViewPageLaunchGameUnlockFpsDescription" xml:space="preserve">
<value>请在游戏内关闭垂直同步选项,需要高性能的显卡以支持更高的帧率</value>
<value>ゲーム内のグラフィック設定で垂直同期を無効にしてください。フレームレートを上げるにはもっと高性能のグラフィックボードが必要となります。</value>
</data>
<data name="ViewPageLaunchGameUnlockFpsHeader" xml:space="preserve">
<value>フレームレート上限解除</value>
</data>
<data name="ViewPageLaunchGameUnlockFpsOff" xml:space="preserve">
<value>禁用</value>
<value>無効</value>
</data>
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>启用</value>
<value>有効</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>HoYo Lab UIDを入力してください</value>
@@ -1899,10 +1980,10 @@
<value>コピー</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutAction" xml:space="preserve">
<value>创建</value>
<value>新規作成</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutDescription" xml:space="preserve">
<value>在桌面上创建默认以管理员方式启动的快捷方式</value>
<value>デスクトップで常に「管理者として実行」のエイリアスを作成する</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutHeader" xml:space="preserve">
<value>ショートカットを作成する</value>
@@ -1914,7 +1995,7 @@
<value>潜在的に危険な機能</value>
</data>
<data name="ViewPageSettingDangerousHint" xml:space="preserve">
<value>除非开发人员明确要求你这么做,否则不应尝试执行下方的操作!</value>
<value>デベロッパーが明確に指示しない限り、以下の機能を有効にすべきではありません。</value>
</data>
<data name="ViewPageSettingDataFolderDescription" xml:space="preserve">
<value>ユーザーデータ/メタデータはここに格納</value>
@@ -1929,7 +2010,7 @@
<value>若祈愿记录缓存刷新频繁提示验证密钥过期,可以尝试此操作</value>
</data>
<data name="ViewPageSettingDeleteCacheHeader" xml:space="preserve">
<value>删除游戏内网页缓存</value>
<value>ゲーム内ブラウザキャッシュを削除する</value>
</data>
<data name="ViewPageSettingDeleteUserDescription" xml:space="preserve">
<value>直接删除用户表的所有记录,用于修复特定的账号冲突问题</value>
@@ -1953,7 +2034,7 @@
<value>表示</value>
</data>
<data name="ViewPageSettingFeaturesDangerousHint" xml:space="preserve">
<value>您解锁了含有违反原神服务条款风险的「启动游戏-高级功能」,将自行承担任何不良后果。</value>
<value>利用規則に違反する可能性のある機能『ゲームランチャー - 上級者向け設定』を有効にしました。ユーザーご自身がそれによって生じる結果について、一切の責任を負うものとなります。</value>
</data>
<data name="ViewPageSettingFeedbackNavigate" xml:space="preserve">
<value>フィードバック</value>
@@ -1977,40 +2058,40 @@
<value>无感验证</value>
</data>
<data name="ViewpageSettingHomeCardDescription" xml:space="preserve">
<value>管理主页仪表板中的卡片</value>
<value>ダッシュボードを整理する</value>
</data>
<data name="ViewpageSettingHomeCardHeader" xml:space="preserve">
<value>主页卡片</value>
<value>ダッシュボード</value>
</data>
<data name="ViewpageSettingHomeCardItemAchievementHeader" xml:space="preserve">
<value>成就管理</value>
<value>アチーブメント</value>
</data>
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
<value>实时便笺</value>
<value>リアルタイムノート</value>
</data>
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
<value>祈愿记录</value>
<value>祈願履歴</value>
</data>
<data name="ViewpageSettingHomeCardItemLaunchGameHeader" xml:space="preserve">
<value>启动游戏</value>
<value>ゲームランチャー</value>
</data>
<data name="ViewPageSettingHomeCardOff" xml:space="preserve">
<value>隐藏</value>
<value>非表示</value>
</data>
<data name="ViewPageSettingHomeCardOn" xml:space="preserve">
<value>示</value>
<value>示</value>
</data>
<data name="ViewpageSettingHomeHeader" xml:space="preserve">
<value>主页</value>
<value>ホーム</value>
</data>
<data name="ViewPageSettingHutaoPassportHeader" xml:space="preserve">
<value>胡桃アカウント</value>
</data>
<data name="ViewPageSettingIsAdvancedLaunchOptionsEnabledDescription" xml:space="preserve">
<value>在完整阅读原神和胡桃工具箱用户协议后,我选择启用「启动游戏-高级功能」</value>
<value>原神およびSnap Hutaoの利用規約を全て熟読し、その後で『ゲームランチャー - 上級者向け設定』を有効にします。</value>
</data>
<data name="ViewPageSettingIsAdvancedLaunchOptionsEnabledHeader" xml:space="preserve">
<value>启动高级功能</value>
<value>上級者向け設定を有効にする</value>
</data>
<data name="ViewPageSettingOfficialSiteNavigate" xml:space="preserve">
<value>公式サイト</value>
@@ -2028,10 +2109,10 @@
<value>更改目录后需要手动移动目录内的数据,否则会重新创建用户数据</value>
</data>
<data name="ViewPageSettingSetDataFolderHeader" xml:space="preserve">
<value>更改数据目录</value>
<value>データディレクトリを変更</value>
</data>
<data name="ViewPageSettingSetGamePathAction" xml:space="preserve">
<value>设置路径</value>
<value>パスを設定する</value>
</data>
<data name="ViewPageSettingSetGamePathHeader" xml:space="preserve">
<value>ゲーム本体の場所を開く</value>
@@ -2043,10 +2124,10 @@
<value>胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号</value>
</data>
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
<value>PowerShell 路径</value>
<value>PowerShell パス</value>
</data>
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
<value>Shell 体验</value>
<value>Shell エクスペリエンス</value>
</data>
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
<value>スポンサーになる</value>
@@ -2055,10 +2136,13 @@
<value>ストレージ</value>
</data>
<data name="ViewPageSettingStorageOpenAction" xml:space="preserve">
<value>打开</value>
<value>開く</value>
</data>
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
<value>更改</value>
<value>変更する</value>
</data>
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>レビューや感想</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>和訳を提供</value>
@@ -2153,6 +2237,12 @@
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>ログインまたはサインアップ</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
<value>角色使用率 = 本层上阵该角色次数(层内重复出现只记一次)/ 持有该角色的深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>战斗数据</value>
</data>
@@ -2163,13 +2253,13 @@
<value>最大ダメージ</value>
</data>
<data name="ViewSpiralAbyssDefaultDescription" xml:space="preserve">
<value>尚未获取任何挑战记录</value>
<value>挑戦履歴はありません</value>
</data>
<data name="ViewSpiralAbyssDefeat" xml:space="preserve">
<value>最多撃破数</value>
</data>
<data name="ViewSpiralAbyssDetail" xml:space="preserve">
<value>詳細</value>
<value>分期详情</value>
</data>
<data name="ViewSpiralAbyssEnergySkill" xml:space="preserve">
<value>元素爆発</value>
@@ -2177,17 +2267,26 @@
<data name="ViewSpiralAbyssHeader" xml:space="preserve">
<value>深境螺旋</value>
</data>
<data name="ViewSpiralAbyssHutaoStatistics" xml:space="preserve">
<value>本期统计</value>
</data>
<data name="ViewSpiralAbyssMaxFloor" xml:space="preserve">
<value>最深到達</value>
</data>
<data name="ViewSpiralAbyssNormalSkill" xml:space="preserve">
<value>元素スキル</value>
</data>
<data name="ViewSpiralAbyssRecordBattleAvatars" xml:space="preserve">
<value>上场角色</value>
</data>
<data name="ViewSpiralAbyssRecordMonsterAttacksMonolith" xml:space="preserve">
<value>攻击地脉镇石</value>
</data>
<data name="ViewSpiralAbyssRefresh" xml:space="preserve">
<value>データを再読み込み</value>
</data>
<data name="ViewSpiralAbyssRefreshDescription" xml:space="preserve">
<value>同步米游社的深渊挑战记录</value>
<value>MiYouSheから深境螺旋の記録を同期</value>
</data>
<data name="ViewSpiralAbyssReveal" xml:space="preserve">
<value>出撃回数</value>
@@ -2214,7 +2313,7 @@
<value>HoYoLAB</value>
</data>
<data name="ViewUserCookieOperation3" xml:space="preserve">
<value>当前用户</value>
<value>現在のユーザー</value>
</data>
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
<value>ウェブ上でログイン</value>
@@ -2226,14 +2325,17 @@
<value>Cookie 再取得</value>
</data>
<data name="ViewUserCookieOperationSignInRewardAction" xml:space="preserve">
<value>领取签到奖励</value>
<value>ログインボーナス獲得</value>
</data>
<data name="ViewUserCopyCookieAction" xml:space="preserve">
<value>复制 Cookie</value>
<value>Cookieをコピーする</value>
</data>
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>ログインしてください</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>ドキュメント</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>CookieTokenを更新しました。</value>
</data>
@@ -2253,7 +2355,7 @@
<value>画像リソースをダウンロード中</value>
</data>
<data name="ViewWelcomeBody" xml:space="preserve">
<value>你可以继续使用电脑,丝毫不受影响</value>
<value>処理に影響されず、引き続きパソコンを使えます</value>
</data>
<data name="ViewWelcomeSubtitle" xml:space="preserve">
<value>アプリを閉じないでください</value>
@@ -2283,7 +2385,7 @@
<value>〓更新时间〓.+?&amp;lt;t class=\"t_(?:gl|lc)\".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>
</data>
<data name="WebAnnouncementMatchVersionUpdateTitle" xml:space="preserve">
<value>\d\.\d版本更新说明</value>
<value>Ver.\d\.\d 更新内容</value>
</data>
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
<value>{0} 日後に開始</value>
@@ -2361,13 +2463,13 @@
<value>利用可能</value>
</data>
<data name="WebDailyNoteTransformerReady" xml:space="preserve">
<value>已准备完成</value>
<value>もうすぐ完成</value>
</data>
<data name="WebDailyNoteTransformerSecondsFormat" xml:space="preserve">
<value>{0} 秒</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-我的角色-实时便笺」页面查看</value>
<value>認証に失敗しました。「MiYouShe - 戦績ツール - リアルタイムノート」で確認し、認証を行ってください</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>UIDは正しくありません</value>
@@ -2382,13 +2484,13 @@
<value>リクエストが多すぎます。時間をおいてから試してください。</value>
</data>
<data name="WebEnkaResponseStatusCode500" xml:space="preserve">
<value>服务器偶发错误</value>
<value>偶発的なサーバーエラー</value>
</data>
<data name="WebEnkaResponseStatusCode503" xml:space="preserve">
<value>服务器严重错误</value>
<value>致命的なサーバーエラー</value>
</data>
<data name="WebEnkaResponseStatusCodeUnknown" xml:space="preserve">
<value>未知的服务器错误</value>
<value>不明なサーバーエラー</value>
</data>
<data name="WebGachaConfigTypeAvatarEventWish" xml:space="preserve">
<value>イベント祈願・キャラクター</value>
@@ -2406,12 +2508,12 @@
<value>イベント祈願・武器</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>状态{0} | 信息{1}</value>
<value>リターンコード{0} | メッセージ{1}</value>
</data>
<data name="WebResponseRefreshCookieHintFormat" xml:space="preserve">
<value>请刷新 Cookie原始消息{0}</value>
</data>
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
<value>[{0}] [{1}] のリクエストにエラーが発生、時間をおいてから試してください</value>
</data>
</root>

View File

@@ -244,7 +244,7 @@
<value>尚未刷新</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>刷新于 {0:yyyy/MM/dd HH:mm:ss}</value>
<value>刷新于 {0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>제 {0} 호</value>
@@ -413,6 +413,87 @@
<value>武器强化素材</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
<value>击败怪物</value>
</data>
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
<value>守护目标</value>
</data>
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
<value>附加:增援怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeDefault" xml:space="preserve">
<value>本间怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
<value>A组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave1" xml:space="preserve">
<value>A组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave2" xml:space="preserve">
<value>A组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave3" xml:space="preserve">
<value>A组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupB" xml:space="preserve">
<value>B组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave1" xml:space="preserve">
<value>B组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave2" xml:space="preserve">
<value>B组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave3" xml:space="preserve">
<value>B组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupC" xml:space="preserve">
<value>C组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave1" xml:space="preserve">
<value>C组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave2" xml:space="preserve">
<value>C组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave3" xml:space="preserve">
<value>C组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupD" xml:space="preserve">
<value>D组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave1" xml:space="preserve">
<value>D组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave2" xml:space="preserve">
<value>D组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave3" xml:space="preserve">
<value>D组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeIndependent" xml:space="preserve">
<value>与其他怪物独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeSuppressed" xml:space="preserve">
<value>暂时没有分波信息</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1" xml:space="preserve">
<value>第一波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
<value>第一波附加:增援第一波怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
<value>第二波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave3" xml:space="preserve">
<value>第三波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
<value>第四波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
<value>请更新角色橱窗数据</value>
</data>
@@ -735,16 +816,16 @@
<value>PowerShell 설치 경로를 찾을 수 없습니다</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>게임 설정 파일을 찾을 수 없습니다 {0}</value>
<value>无法读取游戏配置文件 {0},可能是文件不存在</value>
</data>
<data name="ServiceGameSetMultiChannelUnauthorizedAccess" xml:space="preserve">
<value>설정 파일을 읽거나 쓸 수 없습니다. 관리자 모드로 실행하세요</value>
</data>
<data name="ServiceGameUnlockerFindModuleNoModuleFound" xml:space="preserve">
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成</value>
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成,请重试</value>
</data>
<data name="ServiceGameUnlockerFindModuleTimeLimitExeeded" xml:space="preserve">
<value>在查找必要的模块时遇到问题:查找模块超时</value>
<value>在查找必要的模块时遇到问题:查找模块超时,请重试</value>
</data>
<data name="ServiceGameUnlockerInterestedPatternNotFound" xml:space="preserve">
<value>在匹配内存时遇到问题:无法匹配到期望的内容</value>
@@ -756,7 +837,7 @@
<value>在读取游戏进程内存时遇到问题:无法读取到指定地址的有效值</value>
</data>
<data name="ServiceHutaoUserGachaLogExpiredAt" xml:space="preserve">
<value>祈愿记录上传服务有效期至\n{0:yyyy-MM-dd HH:mm:ss}</value>
<value>祈愿记录上传服务有效期至\n{0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ServiceMetadataFileNotFound" xml:space="preserve">
<value>无法找到缓存的元数据文件</value>
@@ -1293,7 +1374,7 @@
<value>서버 변경 실패</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0}</value>
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
<data name="ViewModelLaunchGamePathInvalid" xml:space="preserve">
<value>게임 경로가 잘못되었습니다. 설정에서 경로를 변경하세요</value>
@@ -1380,7 +1461,7 @@
<value>현재 아카이브 삭제</value>
</data>
<data name="ViewPageAchievementSearchPlaceholder" xml:space="preserve">
<value>업적 이름, 설명 또는 번호 검색</value>
<value>搜索成就名称,描述,版本或编号</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>미완성 우선</value>
@@ -2060,6 +2141,9 @@
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
<value>변경</value>
</data>
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>评价软件</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>번역에 기여하기</value>
</data>
@@ -2153,6 +2237,12 @@
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>회원가입 또는 로그인</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
<value>角色使用率 = 本层上阵该角色次数(层内重复出现只记一次)/ 持有该角色的深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>전투 데이터</value>
</data>
@@ -2169,13 +2259,16 @@
<value>최대 격파 횟수</value>
</data>
<data name="ViewSpiralAbyssDetail" xml:space="preserve">
<value>상세 데이터</value>
<value>分期详情</value>
</data>
<data name="ViewSpiralAbyssEnergySkill" xml:space="preserve">
<value>원소폭발</value>
</data>
<data name="ViewSpiralAbyssHeader" xml:space="preserve">
<value>나선 비경 기록</value>
<value>深境螺旋</value>
</data>
<data name="ViewSpiralAbyssHutaoStatistics" xml:space="preserve">
<value>本期统计</value>
</data>
<data name="ViewSpiralAbyssMaxFloor" xml:space="preserve">
<value>최대 층</value>
@@ -2183,6 +2276,12 @@
<data name="ViewSpiralAbyssNormalSkill" xml:space="preserve">
<value>원소 전투 스킬</value>
</data>
<data name="ViewSpiralAbyssRecordBattleAvatars" xml:space="preserve">
<value>上场角色</value>
</data>
<data name="ViewSpiralAbyssRecordMonsterAttacksMonolith" xml:space="preserve">
<value>攻击地脉镇石</value>
</data>
<data name="ViewSpiralAbyssRefresh" xml:space="preserve">
<value>데이터 동기화</value>
</data>
@@ -2234,6 +2333,9 @@
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>먼저 로그인하세요</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>文档</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>CookieToken을 동기화 했습니다</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>尚未刷新</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>刷新于 {0:yyyy/MM/dd HH:mm:ss}</value>
<value>刷新于 {0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>第 {0} 期</value>
@@ -413,6 +413,87 @@
<value>武器强化素材</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
<value>击败怪物</value>
</data>
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
<value>守护目标</value>
</data>
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
<value>附加:增援怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeDefault" xml:space="preserve">
<value>本间怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
<value>A组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave1" xml:space="preserve">
<value>A组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave2" xml:space="preserve">
<value>A组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave3" xml:space="preserve">
<value>A组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupB" xml:space="preserve">
<value>B组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave1" xml:space="preserve">
<value>B组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave2" xml:space="preserve">
<value>B组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave3" xml:space="preserve">
<value>B组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupC" xml:space="preserve">
<value>C组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave1" xml:space="preserve">
<value>C组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave2" xml:space="preserve">
<value>C组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave3" xml:space="preserve">
<value>C组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupD" xml:space="preserve">
<value>D组不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave1" xml:space="preserve">
<value>D组第一波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave2" xml:space="preserve">
<value>D组第二波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave3" xml:space="preserve">
<value>D组第三波不同的组同时在场各自分波独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeIndependent" xml:space="preserve">
<value>与其他怪物独立</value>
</data>
<data name="ModelMetadataTowerWaveTypeSuppressed" xml:space="preserve">
<value>暂时没有分波信息</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1" xml:space="preserve">
<value>第一波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
<value>第一波附加:增援第一波怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
<value>第二波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave3" xml:space="preserve">
<value>第三波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
<value>第四波:击败所有怪物,下一波才会出现</value>
</data>
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
<value>请更新角色橱窗数据</value>
</data>
@@ -735,16 +816,16 @@
<value>找不到 PowerShell 的安装目录</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>找不到游戏配置文件 {0}</value>
<value>无法读取游戏配置文件 {0},可能是文件不存在</value>
</data>
<data name="ServiceGameSetMultiChannelUnauthorizedAccess" xml:space="preserve">
<value>无法读取或保存配置文件,请以管理员模式重试</value>
</data>
<data name="ServiceGameUnlockerFindModuleNoModuleFound" xml:space="preserve">
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成</value>
<value>在查找必要的模块时遇到问题:无法读取任何模块,可能是保护驱动已经加载完成,请重试</value>
</data>
<data name="ServiceGameUnlockerFindModuleTimeLimitExeeded" xml:space="preserve">
<value>在查找必要的模块时遇到问题:查找模块超时</value>
<value>在查找必要的模块时遇到问题:查找模块超时,请重试</value>
</data>
<data name="ServiceGameUnlockerInterestedPatternNotFound" xml:space="preserve">
<value>在匹配内存时遇到问题:无法匹配到期望的内容</value>
@@ -756,7 +837,7 @@
<value>在读取游戏进程内存时遇到问题:无法读取到指定地址的有效值</value>
</data>
<data name="ServiceHutaoUserGachaLogExpiredAt" xml:space="preserve">
<value>祈愿记录上传服务有效期至\n{0:yyyy-MM-dd HH:mm:ss}</value>
<value>祈愿记录上传服务有效期至\n{0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ServiceMetadataFileNotFound" xml:space="preserve">
<value>无法找到缓存的元数据文件</value>
@@ -1293,7 +1374,7 @@
<value>切换服务器失败</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0}</value>
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
<data name="ViewModelLaunchGamePathInvalid" xml:space="preserve">
<value>游戏路径不正确,前往设置更改游戏路径</value>
@@ -1380,7 +1461,7 @@
<value>删除当前存档</value>
</data>
<data name="ViewPageAchievementSearchPlaceholder" xml:space="preserve">
<value>搜索成就名称,描述或编号</value>
<value>搜索成就名称,描述,版本或编号</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>优先未完成</value>
@@ -2060,6 +2141,9 @@
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
<value>更改</value>
</data>
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>评价软件</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>贡献翻译</value>
</data>
@@ -2153,6 +2237,12 @@
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>立即登录或注册</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
<value>角色使用率 = 本层上阵该角色次数(层内重复出现只记一次)/ 持有该角色的深渊记录总数</value>
</data>
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>战斗数据</value>
</data>
@@ -2169,13 +2259,16 @@
<value>最多击破</value>
</data>
<data name="ViewSpiralAbyssDetail" xml:space="preserve">
<value>详细数据</value>
<value>分期详情</value>
</data>
<data name="ViewSpiralAbyssEnergySkill" xml:space="preserve">
<value>元素爆发</value>
</data>
<data name="ViewSpiralAbyssHeader" xml:space="preserve">
<value>深渊记录</value>
<value>深境螺旋</value>
</data>
<data name="ViewSpiralAbyssHutaoStatistics" xml:space="preserve">
<value>本期统计</value>
</data>
<data name="ViewSpiralAbyssMaxFloor" xml:space="preserve">
<value>最深抵达</value>
@@ -2183,6 +2276,12 @@
<data name="ViewSpiralAbyssNormalSkill" xml:space="preserve">
<value>元素战技</value>
</data>
<data name="ViewSpiralAbyssRecordBattleAvatars" xml:space="preserve">
<value>上场角色</value>
</data>
<data name="ViewSpiralAbyssRecordMonsterAttacksMonolith" xml:space="preserve">
<value>攻击地脉镇石</value>
</data>
<data name="ViewSpiralAbyssRefresh" xml:space="preserve">
<value>刷新数据</value>
</data>
@@ -2234,6 +2333,9 @@
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>请先登录</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>文档</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>刷新 CookieToken 成功</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>尚未刷新</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>刷新於 {0:yyyy/MM/dd HH:mm:ss}</value>
<value>刷新於 {0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>第 {0} 期</value>
@@ -413,6 +413,87 @@
<value>武器強化素材</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ModelMetadataTowerGoalTypeDefeatMonsters" xml:space="preserve">
<value>擊敗怪物</value>
</data>
<data name="ModelMetadataTowerGoalTypeDefendTarget" xml:space="preserve">
<value>守護目標</value>
</data>
<data name="ModelMetadataTowerWaveTypeAdditional" xml:space="preserve">
<value>附加:增援怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeDefault" xml:space="preserve">
<value>本間怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupA" xml:space="preserve">
<value>A組不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave1" xml:space="preserve">
<value>A組第一波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave2" xml:space="preserve">
<value>A組第二波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupAWave3" xml:space="preserve">
<value>A組第三波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupB" xml:space="preserve">
<value>B組不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave1" xml:space="preserve">
<value>B組第一波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave2" xml:space="preserve">
<value>B組第二波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupBWave3" xml:space="preserve">
<value>B組第三波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupC" xml:space="preserve">
<value>C組不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave1" xml:space="preserve">
<value>C組第一波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave2" xml:space="preserve">
<value>C組第二波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupCWave3" xml:space="preserve">
<value>C組第三波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupD" xml:space="preserve">
<value>D組不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave1" xml:space="preserve">
<value>D組第一波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave2" xml:space="preserve">
<value>D組第二波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeGroupDWave3" xml:space="preserve">
<value>D組第三波不同的組同時在場各自分波獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeIndependent" xml:space="preserve">
<value>與其他怪物獨立</value>
</data>
<data name="ModelMetadataTowerWaveTypeSuppressed" xml:space="preserve">
<value>暫時沒有分波訊息</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1" xml:space="preserve">
<value>第一波:擊敗所有怪物,下一波才會出現</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave1Additional" xml:space="preserve">
<value>第一波附加:增援第一波怪物</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave2" xml:space="preserve">
<value>第二波:擊敗所有怪物,下一波才會出現</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave3" xml:space="preserve">
<value>第三波:擊敗所有怪物,下一波才會出現</value>
</data>
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
<value>第四波:擊敗所有怪物,下一波才會出現</value>
</data>
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
<value>請更新角色櫥窗數據</value>
</data>
@@ -735,16 +816,16 @@
<value>找不到 PowerShell 的安裝目錄</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>無法找到遊戲配置檔案 {0}</value>
<value>無法讀取遊戲設定檔 {0},可能是檔案不存在</value>
</data>
<data name="ServiceGameSetMultiChannelUnauthorizedAccess" xml:space="preserve">
<value>無法讀取或保存配置文件,請用管理員模式重試</value>
</data>
<data name="ServiceGameUnlockerFindModuleNoModuleFound" xml:space="preserve">
<value>在尋找必要的模組時遇到問題:無法讀取任何模組,可能是保護驅動已經載入完成</value>
<value>在尋找必要的模組時遇到問題:無法讀取任何模組,可能是保護驅動已經載入完成,請重試</value>
</data>
<data name="ServiceGameUnlockerFindModuleTimeLimitExeeded" xml:space="preserve">
<value>在尋找必要的模組時遇到問題:尋找模組超時</value>
<value>在尋找必要的模組時遇到問題:尋找模組超時,請重試</value>
</data>
<data name="ServiceGameUnlockerInterestedPatternNotFound" xml:space="preserve">
<value>在比對內存時遇到問題:無法比對到期望的內容</value>
@@ -756,7 +837,7 @@
<value>在讀取遊戲程序內存時遇到問題:無法讀取到指定地址的有效值</value>
</data>
<data name="ServiceHutaoUserGachaLogExpiredAt" xml:space="preserve">
<value>祈願錄上傳服務有效期至\n{0:yyyy-MM-dd HH:mm:ss}</value>
<value>祈願錄上傳服務有效期至\n{0:yyyy.MM.dd HH:mm:ss}</value>
</data>
<data name="ServiceMetadataFileNotFound" xml:space="preserve">
<value>無法找到暫存的元數據文件</value>
@@ -906,19 +987,19 @@
<value>為當前存檔導入成就</value>
</data>
<data name="ViewDialogCultivateBatchAvatarLevelTarget" xml:space="preserve">
<value>角色目标等级</value>
<value>角色目標等級</value>
</data>
<data name="ViewDialogCultivateBatchSkillATarget" xml:space="preserve">
<value>普通攻击目标等级</value>
<value>普通攻擊目標等級</value>
</data>
<data name="ViewDialogCultivateBatchSkillETarget" xml:space="preserve">
<value>元素技目标等级</value>
<value>元素技目標等級</value>
</data>
<data name="ViewDialogCultivateBatchSkillQTarget" xml:space="preserve">
<value>元素爆发目标等级</value>
<value>元素爆發目標等級</value>
</data>
<data name="ViewDialogCultivateBatchWeaponLevelTarget" xml:space="preserve">
<value>武器目标等级</value>
<value>武器目標等級</value>
</data>
<data name="ViewDialogCultivateProjectAttachUid" xml:space="preserve">
<value>綁定當前用戶與角色</value>
@@ -930,10 +1011,10 @@
<value>創建新的養成計劃</value>
</data>
<data name="ViewDialogCultivatePromotionDeltaBatchTitle" xml:space="preserve">
<value>批量添加或更新到当前养成计划</value>
<value>批量添加或更新到當前養成計畫</value>
</data>
<data name="ViewDialogCultivatePromotionDeltaTitle" xml:space="preserve">
<value>添加或更新到当前养成计划</value>
<value>添加或更新到當前養成計畫</value>
</data>
<data name="ViewDialogDailyNoteNotificationDailyTaskNotify" xml:space="preserve">
<value>每日委託上線提醒</value>
@@ -1137,7 +1218,7 @@
<value>確定要刪除存檔 {0} 嗎?</value>
</data>
<data name="ViewModelAvatarPropertyBatchCultivateProgressTitle" xml:space="preserve">
<value>取培材料中,请稍候...</value>
<value>取培材料中,請稍後...</value>
</data>
<data name="ViewModelAvatarPropertyCalculateWeaponNull" xml:space="preserve">
<value>當前角色無法計算,請同步信息後再試</value>
@@ -1164,10 +1245,10 @@
<value>養成計劃添加失敗</value>
</data>
<data name="ViewModelCultivationBatchAddCompletedFormat" xml:space="preserve">
<value>操作完成:添加/更新:{0} ,跳 {1} </value>
<value>操作完成:添加/更新:{0} ,跳 {1} </value>
</data>
<data name="ViewModelCultivationBatchAddIncompletedFormat" xml:space="preserve">
<value>操作未全部完成:添加/更新:{0} ,跳 {1} </value>
<value>操作未全部完成:添加/更新:{0} ,跳 {1} </value>
</data>
<data name="ViewModelCultivationEntryAddSuccess" xml:space="preserve">
<value>已成功新增至目前養成計劃</value>
@@ -1293,7 +1374,7 @@
<value>切換伺服器失敗</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>無法讀取遊戲設定文件: {0}</value>
<value>無法讀取遊戲設定檔案: {0},可能是檔案不存在或權限不足</value>
</data>
<data name="ViewModelLaunchGamePathInvalid" xml:space="preserve">
<value>游戲程式路徑不正確,前往設定更改遊戲路徑</value>
@@ -1380,7 +1461,7 @@
<value>刪除當前存檔</value>
</data>
<data name="ViewPageAchievementSearchPlaceholder" xml:space="preserve">
<value>搜索成就名稱,描述或編號</value>
<value>搜索成就名稱,描述,版本或編號</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>優先未完成</value>
@@ -1395,10 +1476,10 @@
<value>聖遺物評分</value>
</data>
<data name="ViewPageAvatarPropertyCalculateAll" xml:space="preserve">
<value>所有角色武器</value>
<value>所有角色武器</value>
</data>
<data name="ViewPageAvatarPropertyCalculateCurrent" xml:space="preserve">
<value>前角色武器</value>
<value>前角色武器</value>
</data>
<data name="ViewPageAvatarPropertyCritScore" xml:space="preserve">
<value>雙暴評分</value>
@@ -1902,7 +1983,7 @@
<value>創建</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutDescription" xml:space="preserve">
<value>在桌面上创建默认以管理方式启动的快捷方式</value>
<value>在桌面上創建預設以管理方式啟動的快捷方式</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutHeader" xml:space="preserve">
<value>創建快捷方式</value>
@@ -1977,31 +2058,31 @@
<value>無感驗證</value>
</data>
<data name="ViewpageSettingHomeCardDescription" xml:space="preserve">
<value>管理主页仪表板中的卡片</value>
<value>管理主頁儀表板中的卡片</value>
</data>
<data name="ViewpageSettingHomeCardHeader" xml:space="preserve">
<value>主卡片</value>
<value>主卡片</value>
</data>
<data name="ViewpageSettingHomeCardItemAchievementHeader" xml:space="preserve">
<value>成就管理</value>
</data>
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
<value>实时便笺</value>
<value>實時便籤</value>
</data>
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
<value>祈愿记录</value>
<value>祈願紀錄</value>
</data>
<data name="ViewpageSettingHomeCardItemLaunchGameHeader" xml:space="preserve">
<value>启动游戏</value>
<value>啟動遊戲</value>
</data>
<data name="ViewPageSettingHomeCardOff" xml:space="preserve">
<value>藏</value>
<value>藏</value>
</data>
<data name="ViewPageSettingHomeCardOn" xml:space="preserve">
<value>示</value>
<value>示</value>
</data>
<data name="ViewpageSettingHomeHeader" xml:space="preserve">
<value>主</value>
<value>主</value>
</data>
<data name="ViewPageSettingHutaoPassportHeader" xml:space="preserve">
<value>Snap Hutao 賬號</value>
@@ -2040,13 +2121,13 @@
<value>設置游戲路徑時請選擇游戲本體YuanShen.exe 或 GenshinImpact.exe 而不是啓動器launcher.exe</value>
</data>
<data name="ViewPageSettingSetPowerShellDescription" xml:space="preserve">
<value>胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号</value>
<value>胡桃使用 PowerShell 更改註冊表中的信息以修改遊戲內賬號</value>
</data>
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
<value>PowerShell 路徑</value>
</data>
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
<value>Shell 体验</value>
<value>Shell 體驗</value>
</data>
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
<value>贊助我們</value>
@@ -2060,6 +2141,9 @@
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
<value>更改</value>
</data>
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>評價軟體</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>貢獻翻譯</value>
</data>
@@ -2153,6 +2237,12 @@
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>立即登入或註冊</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出場率 = 本層上陣該角色次數(層內重複出現只記一次)/ 深淵記錄總數</value>
</data>
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
<value>角色使用率 = 本層上陣該角色次數(層內重複出現只記一次)/ 持有該角色的深淵記錄總數</value>
</data>
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>戰鬥數據</value>
</data>
@@ -2169,13 +2259,16 @@
<value>最多擊破</value>
</data>
<data name="ViewSpiralAbyssDetail" xml:space="preserve">
<value>詳細數據</value>
<value>分期详情</value>
</data>
<data name="ViewSpiralAbyssEnergySkill" xml:space="preserve">
<value>元素爆發</value>
</data>
<data name="ViewSpiralAbyssHeader" xml:space="preserve">
<value>深淵記錄</value>
<value>深境螺旋</value>
</data>
<data name="ViewSpiralAbyssHutaoStatistics" xml:space="preserve">
<value>本期統計</value>
</data>
<data name="ViewSpiralAbyssMaxFloor" xml:space="preserve">
<value>最深抵達</value>
@@ -2183,6 +2276,12 @@
<data name="ViewSpiralAbyssNormalSkill" xml:space="preserve">
<value>元素戰技</value>
</data>
<data name="ViewSpiralAbyssRecordBattleAvatars" xml:space="preserve">
<value>上場角色</value>
</data>
<data name="ViewSpiralAbyssRecordMonsterAttacksMonolith" xml:space="preserve">
<value>攻擊地脈鎮石</value>
</data>
<data name="ViewSpiralAbyssRefresh" xml:space="preserve">
<value>重新整理數據</value>
</data>
@@ -2234,6 +2333,9 @@
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>請先登錄</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>文檔</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>刷新 CookieToken 成功</value>
</data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -13,7 +13,6 @@ using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
using Snap.Hutao.Web.Response;
using System.Runtime.CompilerServices;
using Windows.Perception.Spatial;
using CalculateAvatar = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Avatar;
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;

View File

@@ -4,7 +4,6 @@
using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity.Database;
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
namespace Snap.Hutao.Service.AvatarInfo;

View File

@@ -9,7 +9,6 @@ using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Enka;
using Snap.Hutao.Web.Enka.Model;
using Snap.Hutao.Web.Hoyolab;
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
namespace Snap.Hutao.Service.AvatarInfo;

View File

@@ -6,7 +6,6 @@ using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Format;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.ViewModel.AvatarProperty;
using Snap.Hutao.Web.Enka.Model;
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Cultivation;

View File

@@ -8,7 +8,6 @@ using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Notification;
using System.Globalization;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Service.DailyNote;

View File

@@ -69,9 +69,9 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
// 'ref' is not allowed here because we have lambda below
foreach (Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
{
// Find target history wish to operate.
// Find target history wish to operate. // w.From <= item.Time <= w.To
HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaConfigType.StandardWish or GachaConfigType.NoviceWish)
? historyWishBuilderMap[item.GachaType].FirstOrDefault(w => w.From <= item.Time && w.To >= item.Time)
? historyWishBuilderMap[item.GachaType].BinarySearch(w => item.Time < w.From ? -1 : item.Time > w.To ? 1 : 0)
: default;
switch (item.ItemId.StringLength())

View File

@@ -49,7 +49,7 @@ internal readonly struct GachaItemSaveContext
// 全量刷新
if (!IsLazy)
{
GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId);
GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId);
}
GachaLogDbService.AddGachaItemRange(ItemsToAdd);

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using System.IO;
namespace Snap.Hutao.Service.Game;

View File

@@ -1,20 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO.Ini;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game.Locator;
using Snap.Hutao.Service.Game.Package;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
using Snap.Hutao.Web.Response;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using static Snap.Hutao.Service.Game.GameConstants;
namespace Snap.Hutao.Service.Game;
internal sealed class LaunchStatus

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction;
namespace Snap.Hutao.Service.Game.Unlocker;
/// <summary>

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Web.Hutao;
using Snap.Hutao.Web.Hutao.SpiralAbyss;
namespace Snap.Hutao.Service.Hutao;

View File

@@ -5,11 +5,6 @@ using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Snap.Hutao.Service.Inventroy;

View File

@@ -2,15 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Abstraction;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Achievement;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Service.Metadata;
@@ -18,222 +9,15 @@ namespace Snap.Hutao.Service.Metadata;
/// 元数据服务
/// </summary>
[HighQuality]
[SuppressMessage("", "SA1124")]
internal interface IMetadataService : ICastService
internal interface IMetadataService : ICastService,
IMetadataServiceRawData,
IMetadataServiceIdDataMap,
IMetadataServiceNameDataMap,
IMetadataServiceNameLevelCurveMap
{
/// <summary>
/// 异步初始化服务,尝试更新元数据
/// </summary>
/// <returns>初始化是否成功</returns>
ValueTask<bool> InitializeAsync();
#region RawData
/// <summary>
/// 异步获取成就列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就列表</returns>
ValueTask<List<Model.Metadata.Achievement.Achievement>> GetAchievementsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取成就分类列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就分类列表</returns>
ValueTask<List<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取角色突破列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>角色突破列表</returns>
ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取角色列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>角色列表</returns>
ValueTask<List<Avatar>> GetAvatarsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取卡池配置列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>卡池配置列表</returns>
ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取材料列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>材料列表</returns>
ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取怪物列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>怪物列表</returns>
ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物列表</returns>
ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物强化属性列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物强化属性列表</returns>
ValueTask<List<ReliquarySubAffix>> GetReliquarySubAffixesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物等级数据
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物等级数据</returns>
ValueTask<List<ReliquaryMainAffixLevel>> GetReliquaryLevelsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物主属性强化属性列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物强化属性列表</returns>
ValueTask<List<ReliquaryMainAffix>> GetReliquaryMainAffixesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物套装
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物套装列表</returns>
ValueTask<List<ReliquarySet>> GetReliquarySetsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取武器突破列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>武器突破列表</returns>
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取武器列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>武器列表</returns>
ValueTask<List<Weapon>> GetWeaponsAsync(CancellationToken token = default);
#endregion
#region IdDataMap
/// <summary>
/// 异步获取装备被动Id到圣遗物套装的映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>装备被动Id到圣遗物套装的映射</returns>
ValueTask<Dictionary<EquipAffixId, ReliquarySet>> GetEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default);
ValueTask<Dictionary<ExtendedEquipAffixId, ReliquarySet>> GetExtendedEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取成就映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就映射</returns>
ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取Id到角色的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到角色的字典</returns>
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取显示与材料映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>显示与材料映射</returns>
ValueTask<Dictionary<MaterialId, DisplayItem>> GetIdToDisplayItemAndMaterialMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取Id到材料的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到材料的字典</returns>
ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default(CancellationToken));
/// <summary>
/// 异步获取Id到圣遗物权重的映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到圣遗物权重的字典</returns>
ValueTask<Dictionary<AvatarId, ReliquaryAffixWeight>> GetIdToReliquaryAffixWeightMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取ID到圣遗物副词条的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>字典</returns>
ValueTask<Dictionary<ReliquarySubAffixId, ReliquarySubAffix>> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物主词条Id与属性的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>字典</returns>
ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取ID到武器的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到武器的字典</returns>
ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default);
#endregion
#region NameDataMap
/// <summary>
/// 异步获取名称到角色的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>名称到角色的字典</returns>
ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取名称到武器的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>名称到武器的字典</returns>
ValueTask<Dictionary<string, Weapon>> GetNameToWeaponMapAsync(CancellationToken token = default);
#endregion
#region LevelCurveMap
/// <summary>
/// 异步获取等级角色曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级角色曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取等级怪物曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级怪物曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取等级武器曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级武器曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default);
#endregion
}

View File

@@ -0,0 +1,89 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Tower;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Service.Metadata;
internal interface IMetadataServiceIdDataMap
{
/// <summary>
/// 异步获取装备被动Id到圣遗物套装的映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>装备被动Id到圣遗物套装的映射</returns>
ValueTask<Dictionary<EquipAffixId, ReliquarySet>> GetEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default);
ValueTask<Dictionary<ExtendedEquipAffixId, ReliquarySet>> GetExtendedEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取成就映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就映射</returns>
ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取Id到角色的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到角色的字典</returns>
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取显示与材料映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>显示与材料映射</returns>
ValueTask<Dictionary<MaterialId, DisplayItem>> GetIdToDisplayItemAndMaterialMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取Id到材料的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到材料的字典</returns>
ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default(CancellationToken));
/// <summary>
/// 异步获取Id到圣遗物权重的映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到圣遗物权重的字典</returns>
ValueTask<Dictionary<AvatarId, ReliquaryAffixWeight>> GetIdToReliquaryAffixWeightMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取ID到圣遗物副词条的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>字典</returns>
ValueTask<Dictionary<ReliquarySubAffixId, ReliquarySubAffix>> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物主词条Id与属性的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>字典</returns>
ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default);
ValueTask<Dictionary<TowerScheduleId, TowerSchedule>> GetIdToTowerScheduleMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取ID到武器的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>Id到武器的字典</returns>
ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default);
ValueTask<Dictionary<TowerLevelGroupId, List<TowerLevel>>> GetGroupIdToTowerLevelGroupMapAsync(CancellationToken token = default);
ValueTask<Dictionary<TowerFloorId, TowerFloor>> GetIdToTowerFloorMapAsync(CancellationToken token = default);
ValueTask<Dictionary<MonsterRelationshipId, Monster>> GetRelationshipIdToMonsterMapAsync(CancellationToken token = default);
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Weapon;
namespace Snap.Hutao.Service.Metadata;
internal interface IMetadataServiceNameDataMap
{
/// <summary>
/// 异步获取名称到角色的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>名称到角色的字典</returns>
ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取名称到武器的字典
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>名称到武器的字典</returns>
ValueTask<Dictionary<string, Weapon>> GetNameToWeaponMapAsync(CancellationToken token = default);
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Service.Metadata;
internal interface IMetadataServiceNameLevelCurveMap
{
/// <summary>
/// 异步获取等级角色曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级角色曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取等级怪物曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级怪物曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default);
/// <summary>
/// 异步获取等级武器曲线映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>等级武器曲线映射</returns>
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default);
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Achievement;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Weapon;
namespace Snap.Hutao.Service.Metadata;
internal interface IMetadataServiceRawData
{
/// <summary>
/// 异步获取成就列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就列表</returns>
ValueTask<List<Model.Metadata.Achievement.Achievement>> GetAchievementsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取成就分类列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>成就分类列表</returns>
ValueTask<List<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取角色突破列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>角色突破列表</returns>
ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取角色列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>角色列表</returns>
ValueTask<List<Avatar>> GetAvatarsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取卡池配置列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>卡池配置列表</returns>
ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取材料列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>材料列表</returns>
ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取怪物列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>怪物列表</returns>
ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物列表</returns>
ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物强化属性列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物强化属性列表</returns>
ValueTask<List<ReliquarySubAffix>> GetReliquarySubAffixesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物等级数据
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物等级数据</returns>
ValueTask<List<ReliquaryMainAffixLevel>> GetReliquaryLevelsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物主属性强化属性列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物强化属性列表</returns>
ValueTask<List<ReliquaryMainAffix>> GetReliquaryMainAffixesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取圣遗物套装
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>圣遗物套装列表</returns>
ValueTask<List<ReliquarySet>> GetReliquarySetsAsync(CancellationToken token = default);
/// <summary>
/// 异步获取武器突破列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>武器突破列表</returns>
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取武器列表
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>武器列表</returns>
ValueTask<List<Weapon>> GetWeaponsAsync(CancellationToken token = default);
}

View File

@@ -8,7 +8,6 @@ namespace Snap.Hutao.Service.Metadata;
/// </summary>
internal partial class MetadataService
{
#pragma warning disable CA1823
private const string FileNameAchievement = "Achievement";
private const string FileNameAchievementGoal = "AchievementGoal";
private const string FileNameAvatar = "Avatar";
@@ -31,5 +30,4 @@ internal partial class MetadataService
private const string FileNameWeapon = "Weapon";
private const string FileNameWeaponCurve = "WeaponCurve";
private const string FileNameWeaponPromote = "WeaponPromote";
#pragma warning restore
}

View File

@@ -6,7 +6,9 @@ using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Tower;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
@@ -41,6 +43,21 @@ internal sealed partial class MetadataService
return memoryCache.Set(cacheKey, dict);
}
public async ValueTask<Dictionary<TowerLevelGroupId, List<TowerLevel>>> GetGroupIdToTowerLevelGroupMapAsync(CancellationToken token = default)
{
string cacheKey = $"{nameof(MetadataService)}.Cache.{FileNameTowerLevel}.Map.Group.{nameof(TowerLevelGroupId)}";
if (memoryCache.TryGetValue(cacheKey, out object? value))
{
ArgumentNullException.ThrowIfNull(value);
return (Dictionary<TowerLevelGroupId, List<TowerLevel>>)value;
}
List<TowerLevel> list = await FromCacheOrFileAsync<List<TowerLevel>>(FileNameTowerLevel, token).ConfigureAwait(false);
Dictionary<TowerLevelGroupId, List<TowerLevel>> dict = list.GroupBy(l => l.GroupId).ToDictionary(g => g.Key, g => g.ToList());
return memoryCache.Set(cacheKey, dict);
}
/// <inheritdoc/>
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
{
@@ -102,6 +119,16 @@ internal sealed partial class MetadataService
return FromCacheAsDictionaryAsync<ReliquaryMainAffixId, FightProperty, ReliquaryMainAffix>(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token);
}
public ValueTask<Dictionary<TowerFloorId, TowerFloor>> GetIdToTowerFloorMapAsync(CancellationToken token = default)
{
return FromCacheAsDictionaryAsync<TowerFloorId, TowerFloor>(FileNameTowerFloor, t => t.Id, token);
}
public ValueTask<Dictionary<TowerScheduleId, TowerSchedule>> GetIdToTowerScheduleMapAsync(CancellationToken token = default)
{
return FromCacheAsDictionaryAsync<TowerScheduleId, TowerSchedule>(FileNameTowerSchedule, t => t.Id, token);
}
/// <inheritdoc/>
public ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default)
{
@@ -126,6 +153,11 @@ internal sealed partial class MetadataService
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameWeaponCurve, w => w.Level, w => w.Map, token);
}
public ValueTask<Dictionary<MonsterRelationshipId, Monster>> GetRelationshipIdToMonsterMapAsync(CancellationToken token = default)
{
return FromCacheAsDictionaryAsync<MonsterRelationshipId, Monster>(FileNameMonster, m => m.RelationshipId, token);
}
/// <inheritdoc/>
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
{

View File

@@ -0,0 +1,45 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.View.Page;
namespace Snap.Hutao.Service.Navigation;
[Injection(InjectAs.Singleton, typeof(IDocumentationProvider))]
[ConstructorGenerated]
internal sealed partial class DocumentationProvider : IDocumentationProvider
{
private const string Home = "https://hut.ao";
private static readonly Dictionary<Type, string> TypeDocumentations = new()
{
[typeof(AchievementPage)] = "https://hut.ao/features/achievements.html",
[typeof(AnnouncementPage)] = "https://hut.ao/features/dashboard.html",
[typeof(AvatarPropertyPage)] = "https://hut.ao/features/character-data.html",
[typeof(CultivationPage)] = "https://hut.ao/features/develop-plan.html",
[typeof(DailyNotePage)] = "https://hut.ao/features/real-time-notes.html",
[typeof(GachaLogPage)] = "https://hut.ao/features/wish-export.html",
[typeof(HutaoPassportPage)] = "https://hut.ao/zh/features/hutao-settings.html#%E8%83%A1%E6%A1%83%E5%B8%90%E5%8F%B7",
[typeof(LaunchGamePage)] = "https://hut.ao/features/game-launcher.html",
[typeof(LoginHoyoverseUserPage)] = "https://hut.ao/features/mhy-account-switch.html",
[typeof(LoginMihoyoUserPage)] = "https://hut.ao/features/mhy-account-switch.html",
[typeof(SettingPage)] = "https://hut.ao/features/hutao-settings.html",
[typeof(SpiralAbyssRecordPage)] = "https://hut.ao/features/dashboard.html",
[typeof(TestPage)] = Home,
[typeof(WikiAvatarPage)] = "https://hut.ao/features/character-wiki.html",
[typeof(WikiMonsterPage)] = "https://hut.ao/features/monster-wiki.html",
[typeof(WikiWeaponPage)] = "https://hut.ao/features/weapon-wiki.html",
};
private readonly INavigationService navigationService;
public string GetDocumentation()
{
if (navigationService.Current is { } type)
{
return TypeDocumentations[type];
}
return Home;
}
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Navigation;
internal interface IDocumentationProvider
{
string GetDocumentation();
}

View File

@@ -10,7 +10,7 @@ namespace Snap.Hutao.Service.Navigation;
/// 导航服务
/// </summary>
[HighQuality]
internal interface INavigationService : ICastService
internal interface INavigationService : ICastService, INavigationCurrent
{
/// <summary>
/// 导航到指定类型的页面
@@ -48,3 +48,8 @@ internal interface INavigationService : ICastService
/// </summary>
void GoBack();
}
internal interface INavigationCurrent
{
Type? Current { get; }
}

View File

@@ -43,6 +43,8 @@ internal sealed class NavigationService : INavigationService, INavigationInitial
paneClosedEventHandler = OnPaneStateChanged;
}
public Type? Current { get => frame?.Content.GetType(); }
private NavigationView? NavigationView
{
get => navigationView;

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.SpiralAbyss;
@@ -10,7 +9,7 @@ internal interface ISpiralAbyssRecordDbService
{
ValueTask AddSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssEntryCollectionByUidAsync(string uid);
ValueTask<Dictionary<uint, SpiralAbyssEntry>> GetSpiralAbyssEntryListByUidAsync(string uid);
ValueTask UpdateSpiralAbyssEntryAsync(SpiralAbyssEntry entry);
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
using Snap.Hutao.ViewModel.SpiralAbyss;
using Snap.Hutao.ViewModel.User;
using System.Collections.ObjectModel;
@@ -18,7 +18,9 @@ internal interface ISpiralAbyssRecordService
/// </summary>
/// <param name="userAndUid">当前角色</param>
/// <returns>深渊记录集合</returns>
ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssCollectionAsync(UserAndUid userAndUid);
ValueTask<ObservableCollection<SpiralAbyssView>> GetSpiralAbyssViewCollectionAsync(UserAndUid userAndUid);
ValueTask<bool> InitializeAsync();
/// <summary>
/// 异步刷新深渊记录

View File

@@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.SpiralAbyss;
@@ -15,19 +14,18 @@ internal sealed partial class SpiralAbyssRecordDbService : ISpiralAbyssRecordDbS
{
private readonly IServiceProvider serviceProvider;
public async ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssEntryCollectionByUidAsync(string uid)
public async ValueTask<Dictionary<uint, SpiralAbyssEntry>> GetSpiralAbyssEntryListByUidAsync(string uid)
{
using (IServiceScope scope = serviceProvider.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
List<SpiralAbyssEntry> entries = await appDbContext.SpiralAbysses
.Where(s => s.Uid == uid)
.OrderByDescending(s => s.ScheduleId)
.ToListAsync()
.ConfigureAwait(false);
return entries.ToObservableCollection();
return entries.ToDictionary(e => e.ScheduleId);
}
}

View File

@@ -3,6 +3,9 @@
using Snap.Hutao.Core.DependencyInjection.Abstraction;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.ViewModel.SpiralAbyss;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
using Snap.Hutao.Web.Response;
@@ -18,15 +21,35 @@ namespace Snap.Hutao.Service.SpiralAbyss;
[Injection(InjectAs.Scoped, typeof(ISpiralAbyssRecordService))]
internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordService
{
private readonly ITaskContext taskContext;
private readonly IOverseaSupportFactory<IGameRecordClient> gameRecordClientFactory;
private readonly ISpiralAbyssRecordDbService spiralAbyssRecordDbService;
private readonly IMetadataService metadataService;
private readonly ITaskContext taskContext;
private string? uid;
private ObservableCollection<SpiralAbyssEntry>? spiralAbysses;
private ObservableCollection<SpiralAbyssView>? spiralAbysses;
private SpiralAbyssMetadataContext? metadataContext;
public async ValueTask<bool> InitializeAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
metadataContext = new()
{
IdScheduleMap = await metadataService.GetIdToTowerScheduleMapAsync().ConfigureAwait(false),
IdFloorMap = await metadataService.GetIdToTowerFloorMapAsync().ConfigureAwait(false),
IdLevelGroupMap = await metadataService.GetGroupIdToTowerLevelGroupMapAsync().ConfigureAwait(false),
IdMonsterMap = await metadataService.GetRelationshipIdToMonsterMapAsync().ConfigureAwait(false),
IdAvatarMap = AvatarIds.WithPlayers(await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false)),
};
return true;
}
return false;
}
/// <inheritdoc/>
public async ValueTask<ObservableCollection<SpiralAbyssEntry>> GetSpiralAbyssCollectionAsync(UserAndUid userAndUid)
public async ValueTask<ObservableCollection<SpiralAbyssView>> GetSpiralAbyssViewCollectionAsync(UserAndUid userAndUid)
{
if (uid != userAndUid.Uid.Value)
{
@@ -34,9 +57,18 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi
}
uid = userAndUid.Uid.Value;
spiralAbysses ??= await spiralAbyssRecordDbService
.GetSpiralAbyssEntryCollectionByUidAsync(userAndUid.Uid.Value)
.ConfigureAwait(false);
if (spiralAbysses is null)
{
Dictionary<uint, SpiralAbyssEntry> entryMap = await spiralAbyssRecordDbService
.GetSpiralAbyssEntryListByUidAsync(userAndUid.Uid.Value)
.ConfigureAwait(false);
ArgumentNullException.ThrowIfNull(metadataContext);
spiralAbysses = metadataContext.IdScheduleMap.Values
.Select(sch => SpiralAbyssView.From(entryMap.GetValueOrDefault(sch.Id), sch, metadataContext))
.Reverse()
.ToObservableCollection();
}
return spiralAbysses;
}
@@ -44,6 +76,12 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi
/// <inheritdoc/>
public async ValueTask RefreshSpiralAbyssAsync(UserAndUid userAndUid)
{
// request the index first
await gameRecordClientFactory
.Create(userAndUid.User.IsOversea)
.GetPlayerInfoAsync(userAndUid)
.ConfigureAwait(false);
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Last).ConfigureAwait(false);
await RefreshSpiralAbyssCoreAsync(userAndUid, SpiralAbyssSchedule.Current).ConfigureAwait(false);
}
@@ -60,23 +98,31 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi
Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.SpiralAbyss webSpiralAbyss = response.Data;
ArgumentNullException.ThrowIfNull(spiralAbysses);
if (spiralAbysses.SingleOrDefault(s => s.ScheduleId == webSpiralAbyss.ScheduleId) is { } existEntry)
{
await taskContext.SwitchToMainThreadAsync();
existEntry.UpdateSpiralAbyss(webSpiralAbyss);
ArgumentNullException.ThrowIfNull(metadataContext);
await taskContext.SwitchToBackgroundAsync();
await spiralAbyssRecordDbService.UpdateSpiralAbyssEntryAsync(existEntry).ConfigureAwait(false);
}
else
int index = spiralAbysses.FirstIndexOf(s => s.ScheduleId == webSpiralAbyss.ScheduleId);
if (index >= 0)
{
SpiralAbyssEntry newEntry = SpiralAbyssEntry.From(userAndUid.Uid.Value, webSpiralAbyss);
await taskContext.SwitchToBackgroundAsync();
SpiralAbyssView view = spiralAbysses[index];
SpiralAbyssEntry targetEntry;
if (view.Entity is not null)
{
view.Entity.SpiralAbyss = webSpiralAbyss;
await spiralAbyssRecordDbService.UpdateSpiralAbyssEntryAsync(view.Entity).ConfigureAwait(false);
targetEntry = view.Entity;
}
else
{
SpiralAbyssEntry newEntry = SpiralAbyssEntry.From(userAndUid.Uid.Value, webSpiralAbyss);
await spiralAbyssRecordDbService.AddSpiralAbyssEntryAsync(newEntry).ConfigureAwait(false);
targetEntry = newEntry;
}
await taskContext.SwitchToMainThreadAsync();
spiralAbysses.Insert(0, newEntry);
await taskContext.SwitchToBackgroundAsync();
await spiralAbyssRecordDbService.AddSpiralAbyssEntryAsync(newEntry).ConfigureAwait(false);
spiralAbysses.RemoveAt(index);
spiralAbysses.Insert(index, SpiralAbyssView.From(targetEntry, metadataContext));
}
}
}

View File

@@ -72,6 +72,7 @@
<None Remove="Assets\Wide310x150Logo.scale-200.png" />
<None Remove="Assets\Wide310x150Logo.scale-400.png" />
<None Remove="CodeMetricsConfig.txt" />
<None Remove="Control\Loading.xaml" />
<None Remove="Control\Panel\PanelSelector.xaml" />
<None Remove="Control\Theme\FontStyle.xaml" />
<None Remove="GuideWindow.xaml" />
@@ -95,6 +96,7 @@
<None Remove="Resource\Navigation\Cultivation.png" />
<None Remove="Resource\Navigation\DailyNote.png" />
<None Remove="Resource\Navigation\Database.png" />
<None Remove="Resource\Navigation\Documentation.png" />
<None Remove="Resource\Navigation\GachaLog.png" />
<None Remove="Resource\Navigation\LaunchGame.png" />
<None Remove="Resource\Navigation\SpiralAbyss.png" />
@@ -121,7 +123,7 @@
<None Remove="View\Control\SkillPivot.xaml" />
<None Remove="View\Control\StatisticsCard.xaml" />
<None Remove="View\Control\StatisticsSegmented.xaml" />
<None Remove="View\Control\Webview2Viewer.xaml" />
<None Remove="View\Control\WebViewer.xaml" />
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
@@ -146,7 +148,6 @@
<None Remove="View\Page\CultivationPage.xaml" />
<None Remove="View\Page\DailyNotePage.xaml" />
<None Remove="View\Page\GachaLogPage.xaml" />
<None Remove="View\Page\HutaoDatabasePage.xaml" />
<None Remove="View\Page\HutaoPassportPage.xaml" />
<None Remove="View\Page\LaunchGamePage.xaml" />
<None Remove="View\Page\LoginMihoyoUserPage.xaml" />
@@ -223,6 +224,7 @@
<Content Include="Resource\Navigation\Cultivation.png" />
<Content Include="Resource\Navigation\DailyNote.png" />
<Content Include="Resource\Navigation\Database.png" />
<Content Include="Resource\Navigation\Documentation.png" />
<Content Include="Resource\Navigation\GachaLog.png" />
<Content Include="Resource\Navigation\LaunchGame.png" />
<Content Include="Resource\Navigation\SpiralAbyss.png" />
@@ -242,15 +244,15 @@
<PackageReference Include="CommunityToolkit.Labs.WinUI.TransitionHelper" Version="0.1.230809" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2-build.1" />
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Collections" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.HeaderedControls" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Core" Version="7.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -302,6 +304,12 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Page Update="Control\Loading.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Dialog\CultivatePromotionDeltaBatchDialog.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -321,7 +329,7 @@
</ItemGroup>
<ItemGroup>
<Page Update="View\Control\Webview2Viewer.xaml">
<Page Update="View\Control\WebViewer.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
@@ -467,11 +475,6 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\HutaoDatabasePage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Dialog\GachaLogUrlDialog.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -11,4 +11,8 @@
Content="{shcm:ResourceString Name=ViewControlElevationText}"
Foreground="{ThemeResource SystemFillColorCriticalBrush}"
Icon="{shcm:FontIcon Glyph=&#xE7BA;}"
mc:Ignorable="d"/>
mc:Ignorable="d">
<clw:TokenItem.Resources>
<x:Double x:Key="ListViewItemDisabledThemeOpacity">1</x:Double>
</clw:TokenItem.Resources>
</clw:TokenItem>

View File

@@ -0,0 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.ViewModel.User;
namespace Snap.Hutao.View.Control;
internal interface IWebViewerSource
{
string GetSource(UserAndUid userAndUid);
}

View File

@@ -1,102 +1,29 @@
<cwuc:Loading
<shc:Loading
x:Class="Snap.Hutao.View.Control.LoadingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clw="using:CommunityToolkit.Labs.WinUI"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
mc:Ignorable="d">
<cwuc:Loading.Style>
<Style TargetType="cwuc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cwuc:Loading">
<Border
x:Name="RootGrid"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Opacity="0"
Visibility="Collapsed">
<Grid>
<clw:Shimmer IsActive="{x:Bind IsLoading, Mode=OneWay}"/>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<shci:CachedImage
Width="120"
Height="120"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon272}"/>
<TextBlock
Margin="0,16,0,0"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewControlLoadingText}"/>
</StackPanel>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="LoadingIn">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LoadingOut">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</cwuc:Loading.Style>
</cwuc:Loading>
<Grid>
<clw:Shimmer IsActive="{x:Bind IsLoading, Mode=OneWay}"/>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<shci:CachedImage
Width="120"
Height="120"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon272}"/>
<TextBlock
Margin="0,16,0,0"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewControlLoadingText}"/>
</StackPanel>
</Grid>
</shc:Loading>

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Controls;
using Snap.Hutao.Control;
namespace Snap.Hutao.View.Control;

View File

@@ -1,86 +1,14 @@
<cwuc:Loading
<shc:Loading
x:Class="Snap.Hutao.View.Control.LoadingViewSlim"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clw="using:CommunityToolkit.Labs.WinUI"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shc="using:Snap.Hutao.Control"
Height="{StaticResource HomeAdaptiveCardHeight}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
mc:Ignorable="d">
<cwuc:Loading.Style>
<Style TargetType="cwuc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cwuc:Loading">
<Border
x:Name="RootGrid"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Opacity="0"
Visibility="Collapsed">
<clw:Shimmer IsActive="{x:Bind IsLoading}" Duration="0:0:1"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="LoadingIn">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LoadingOut">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</cwuc:Loading.Style>
</cwuc:Loading>
<clw:Shimmer IsActive="{x:Bind IsLoading}" Duration="0:0:1"/>
</shc:Loading>

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Controls;
using Snap.Hutao.Control;
namespace Snap.Hutao.View.Control;

View File

@@ -0,0 +1,16 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.ViewModel.User;
namespace Snap.Hutao.View.Control;
[DependencyProperty("Source", typeof(string))]
internal sealed partial class StaticWebview2ViewerSource : DependencyObject, IWebViewerSource
{
public string GetSource(UserAndUid userAndUid)
{
return Source;
}
}

View File

@@ -2,8 +2,8 @@
x:Class="Snap.Hutao.View.Control.StatisticsCard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls"
xmlns:cwconv="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shch="using:Snap.Hutao.Control.Helper"
@@ -78,7 +78,7 @@
</Grid>
</DataTemplate>
<cwuc:BoolToObjectConverter
<cwconv:BoolToObjectConverter
x:Key="BoolToBrushConverter"
FalseValue="{ThemeResource SystemFillColorCriticalBackgroundBrush}"
TrueValue="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
@@ -238,11 +238,11 @@
HorizontalAlignment="Stretch"
IsPredictPullAvailable="{Binding IsPredictPullAvailable}"
SelectedIndex="0"/>
<cwc:SwitchPresenter
<cwcont:SwitchPresenter
Height="85"
Padding="0,12"
Value="{x:Bind StatisticsSegmented.SelectedIndex, Mode=OneWay}">
<cwc:Case Value="{shcm:Int32 Value=0}">
<cwcont:Case Value="{shcm:Int32 Value=0}">
<StackPanel Spacing="2">
<Grid>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeAveragePullText}"/>
@@ -274,8 +274,8 @@
Text="{Binding MinOrangePullFormatted}"/>
</Grid>
</StackPanel>
</cwc:Case>
<cwc:Case Value="{shcm:Int32 Value=1}">
</cwcont:Case>
<cwcont:Case Value="{shcm:Int32 Value=1}">
<StackPanel Spacing="2">
<Grid>
<TextBlock
@@ -314,28 +314,28 @@
Text="{Binding TotalBlueFormatted}"/>
</Grid>
</StackPanel>
</cwc:Case>
<cwc:Case Value="{shcm:Int32 Value=2}">
</cwcont:Case>
<cwcont:Case Value="{shcm:Int32 Value=2}">
<StackPanel Spacing="2">
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{Binding PredictedPullLeftToOrangeFormatted}"/>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{Binding ProbabilityOfNextPullIsOrangeFormatted}"/>
</StackPanel>
</cwc:Case>
</cwc:SwitchPresenter>
</cwcont:Case>
</cwcont:SwitchPresenter>
<MenuFlyoutSeparator Margin="-12,0,-12,0"/>
</StackPanel>
</Expander>
<cwc:SwitchPresenter
<cwcont:SwitchPresenter
Grid.Row="2"
Margin="12,6,12,12"
Value="{Binding ElementName=ItemsPanelSelector, Path=Current}">
<cwc:SwitchPresenter.ContentTransitions>
<cwcont:SwitchPresenter.ContentTransitions>
<TransitionCollection>
<ContentThemeTransition/>
</TransitionCollection>
</cwc:SwitchPresenter.ContentTransitions>
<cwc:Case Value="List">
</cwcont:SwitchPresenter.ContentTransitions>
<cwcont:Case Value="List">
<ListView
ItemTemplate="{StaticResource OrangeListTemplate}"
ItemsSource="{Binding OrangeList}"
@@ -348,8 +348,8 @@
</Style>
</ListView.ItemContainerStyle>
</ListView>
</cwc:Case>
<cwc:Case Value="Grid">
</cwcont:Case>
<cwcont:Case Value="Grid">
<GridView
Margin="0,0,-4,0"
ItemTemplate="{StaticResource OrangeGridTemplate}"
@@ -363,8 +363,8 @@
</Style>
</GridView.ItemContainerStyle>
</GridView>
</cwc:Case>
</cwc:SwitchPresenter>
</cwcont:Case>
</cwcont:SwitchPresenter>
</Grid>
</Border>
</UserControl>

View File

@@ -1,9 +1,8 @@
<UserControl
x:Class="Snap.Hutao.View.Control.Webview2Viewer"
x:Class="Snap.Hutao.View.Control.WebViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Snap.Hutao.View.Control"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Transitions>
@@ -15,4 +14,4 @@
x:Name="WebView"
Margin="0"
DefaultBackgroundColor="Transparent"/>
</UserControl>
</UserControl>

View File

@@ -0,0 +1,107 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Message;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Bridge;
using System.Diagnostics;
namespace Snap.Hutao.View.Control;
[DependencyProperty("SourceProvider", typeof(IWebViewerSource))]
internal partial class WebViewer : UserControl, IRecipient<UserChangedMessage>
{
private readonly IServiceProvider serviceProvider;
private readonly RoutedEventHandler loadEventHandler;
private readonly RoutedEventHandler unloadEventHandler;
[SuppressMessage("", "IDE0052")]
private MiHoYoJSInterface? jsInterface;
public WebViewer()
{
InitializeComponent();
serviceProvider = Ioc.Default;
serviceProvider.GetRequiredService<IMessenger>().Register(this);
loadEventHandler = OnLoaded;
unloadEventHandler = OnUnloaded;
Loaded += loadEventHandler;
Unloaded += unloadEventHandler;
}
public void Receive(UserChangedMessage message)
{
if (message.NewValue?.SelectedUserGameRole is null)
{
return;
}
ITaskContext taskContext = serviceProvider.GetRequiredService<ITaskContext>();
taskContext.InvokeOnMainThread(RefreshWebview2Content);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
InitializeAsync().SafeForget();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
jsInterface = null;
Loaded -= loadEventHandler;
Unloaded -= unloadEventHandler;
}
private async ValueTask InitializeAsync()
{
await WebView.EnsureCoreWebView2Async();
RefreshWebview2Content();
}
private async void RefreshWebview2Content()
{
User? user = serviceProvider.GetRequiredService<IUserService>().Current;
if (user is null)
{
return;
}
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
if (SourceProvider is not null)
{
if (UserAndUid.TryFromUser(user, out UserAndUid? userAndUid))
{
string source = SourceProvider.GetSource(userAndUid);
if (!string.IsNullOrEmpty(source))
{
foreach (CoreWebView2Cookie cookie in await coreWebView2.CookieManager.GetCookiesAsync(".mihoyo.com"))
{
coreWebView2.CookieManager.DeleteCookie(cookie);
}
coreWebView2.SetCookie(user.CookieToken, user.LToken, user.SToken).SetMobileUserAgent();
jsInterface = serviceProvider.CreateInstance<MiHoYoJSInterface>(coreWebView2, userAndUid);
CoreWebView2Navigator navigator = new(coreWebView2);
await navigator.NavigateAsync("about:blank");
Debug.WriteLine($"Before {source}");
await navigator.NavigateAsync(source);
Debug.WriteLine($"After {WebView.Source}");
}
}
else
{
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.MustSelectUserAndUid);
}
}
}
}

View File

@@ -1,90 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Bridge;
namespace Snap.Hutao.View.Control;
[DependencyProperty("Source", typeof(string), default(string)!, nameof(OnSourceChanged))]
[DependencyProperty("User", typeof(User))]
internal partial class Webview2Viewer : UserControl
{
private readonly IServiceProvider serviceProvider;
private readonly RoutedEventHandler loadEventHandler;
private readonly RoutedEventHandler unloadEventHandler;
private MiHoYoJSInterface? jsInterface;
private bool isInitialized;
public Webview2Viewer()
{
InitializeComponent();
serviceProvider = Ioc.Default;
loadEventHandler = OnLoaded;
unloadEventHandler = OnUnloaded;
Loaded += loadEventHandler;
Unloaded += unloadEventHandler;
}
private static void OnSourceChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
Webview2Viewer viewer = (Webview2Viewer)dp;
if (viewer.isInitialized)
{
viewer.RefreshWebview2Content();
}
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
InitializeAsync().SafeForget();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
jsInterface = null;
Loaded -= loadEventHandler;
Unloaded -= unloadEventHandler;
}
private async ValueTask InitializeAsync()
{
await WebView.EnsureCoreWebView2Async();
RefreshWebview2Content();
}
private void RefreshWebview2Content()
{
if (User is null)
{
IUserService userService = serviceProvider.GetRequiredService<IUserService>();
User ??= userService.Current;
if (User is null)
{
return;
}
}
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
if (UserAndUid.TryFromUser(User, out UserAndUid? userAndUid) && !string.IsNullOrEmpty(Source))
{
coreWebView2.SetCookie(User.CookieToken, User.LToken, User.SToken).SetMobileUserAgent();
jsInterface = serviceProvider.CreateInstance<MiHoYoJSInterface>(coreWebView2, userAndUid);
coreWebView2.Navigate(Source);
}
else
{
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.MustSelectUserAndUid);
}
isInitialized = true;
}
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Converters;
using CommunityToolkit.WinUI.Converters;
using Microsoft.UI.Xaml;
namespace Snap.Hutao.View.Converter;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Converters;
using CommunityToolkit.WinUI.Converters;
namespace Snap.Hutao.View.Converter;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Converters;
using CommunityToolkit.WinUI.Converters;
namespace Snap.Hutao.View.Converter;

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