Compare commits

..

1 Commits

Author SHA1 Message Date
qhy040404
a02162f76d refresh data folder size after deleting server cache 2024-01-05 23:30:16 +08:00
97 changed files with 726 additions and 2254 deletions

View File

@@ -124,6 +124,9 @@ dotnet_diagnostic.SA1623.severity = none
# SA1636: File header copyright text should match
dotnet_diagnostic.SA1636.severity = none
# SA1414: Tuple types in signatures should have element names
dotnet_diagnostic.SA1414.severity = none
# SA0001: XML comment analysis disabled
dotnet_diagnostic.SA0001.severity = none
csharp_style_prefer_parameter_null_checking = true:suggestion
@@ -322,6 +325,7 @@ dotnet_diagnostic.CA2227.severity = suggestion
# CA2251: 使用 “string.Equals”
dotnet_diagnostic.CA2251.severity = suggestion
csharp_style_prefer_primary_constructors = true:suggestion
dotnet_diagnostic.SA1010.severity = none
[*.vb]
#### 命名样式 ####

View File

@@ -1,15 +1,4 @@
// ADVAPI32
RegCloseKey
RegOpenKeyExW
RegNotifyChangeKeyValue
REG_NOTIFY_FILTER
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
// COMCTL32
// COMCTL32
DefSubclassProc
RemoveWindowSubclass
SetWindowSubclass
@@ -58,14 +47,12 @@ GetCursorPos
GetDC
GetDpiForWindow
GetForegroundWindow
GetWindowLongPtrW
GetWindowPlacement
GetWindowThreadProcessId
ReleaseDC
RegisterHotKey
SendInput
SetForegroundWindow
SetWindowLongPtrW
UnregisterHotKey
// COM
@@ -87,7 +74,6 @@ E_FAIL
INFINITE
RPC_E_WRONG_THREAD
MAX_PATH
WM_ERASEBKGND
WM_GETMINMAXINFO
WM_HOTKEY
WM_NCRBUTTONDOWN
@@ -103,7 +89,6 @@ LPTHREAD_START_ROUTINE
// UI.WindowsAndMessaging
MINMAXINFO
WINDOW_EX_STYLE
// System.Com
CWMO_FLAGS

View File

@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,72 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Windows.Win32.CsWin32.InteropServices;
internal class WinRTCustomMarshaler : ICustomMarshaler
{
private static readonly string? AssemblyFullName = typeof(Windows.Foundation.IMemoryBuffer).Assembly.FullName;
private readonly string className;
private bool lookedForFromAbi;
private MethodInfo? fromAbiMethod;
private WinRTCustomMarshaler(string className)
{
this.className = className;
}
public static ICustomMarshaler GetInstance(string cookie)
{
return new WinRTCustomMarshaler(cookie);
}
public void CleanUpManagedData(object ManagedObj)
{
}
public void CleanUpNativeData(nint pNativeData)
{
Marshal.Release(pNativeData);
}
public int GetNativeDataSize()
{
throw new NotSupportedException();
}
public nint MarshalManagedToNative(object ManagedObj)
{
throw new NotSupportedException();
}
public object MarshalNativeToManaged(nint thisPtr)
{
return className switch
{
"Windows.System.DispatcherQueueController" => Windows.System.DispatcherQueueController.FromAbi(thisPtr),
_ => MarshalNativeToManagedSlow(thisPtr),
};
}
private object MarshalNativeToManagedSlow(nint pNativeData)
{
if (!lookedForFromAbi)
{
Type? type = Type.GetType($"{className}, {AssemblyFullName}");
fromAbiMethod = type?.GetMethod("FromAbi");
lookedForFromAbi = true;
}
if (fromAbiMethod is not null)
{
return fromAbiMethod.Invoke(default, new object[] { pNativeData })!;
}
else
{
return Marshal.GetObjectForIUnknown(pNativeData);
}
}
}

View File

@@ -7,7 +7,6 @@ namespace Snap.Hutao.Control;
[TemplateVisualState(Name = "LoadingIn", GroupName = "CommonStates")]
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
[TemplatePart(Name = "ContentGrid", Type = typeof(FrameworkElement))]
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));

View File

@@ -3,9 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shc="using:Snap.Hutao.Control">
<Style BasedOn="{StaticResource DefaultLoadingStyle}" TargetType="shc:Loading"/>
<Style x:Key="DefaultLoadingStyle" TargetType="shc:Loading">
<Style TargetType="shc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>

View File

@@ -18,15 +18,12 @@ internal sealed class FontIconExtension : MarkupExtension
/// </summary>
public string Glyph { get; set; } = default!;
public double FontSize { get; set; } = 12;
/// <inheritdoc/>
protected override object ProvideValue()
{
return new FontIcon()
{
Glyph = Glyph,
FontSize = FontSize,
};
}
}

View File

@@ -156,7 +156,7 @@ internal sealed partial class HtmlDescriptionTextBlock : ContentControl
text.Inlines.Add(new Run
{
Text = slice.ToString(),
FontWeight = FontWeights.SemiBold,
FontWeight = FontWeights.Bold,
});
}

View File

@@ -20,9 +20,6 @@
<ItemsPanelTemplate x:Key="StackPanelSpacing4Template">
<StackPanel Spacing="4"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="StackPanelSpacing8Template">
<StackPanel Spacing="8"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="UniformGridColumns2Spacing2Template">
<cwcont:UniformGrid
ColumnSpacing="2"

View File

@@ -6,12 +6,6 @@
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
<x:Double x:Key="SettingsCardContentControlMinWidth">120</x:Double>
<x:Double x:Key="SettingsCardContentControlMinWidth2">160</x:Double>
<x:Double x:Key="SettingsCardContentControlSpacing">10</x:Double>
<Thickness x:Key="SettingsCardAlignSettingsExpanderPadding">16,16,44,16</Thickness>
<Thickness x:Key="SettingsExpanderItemHasIconPadding">16,8,16,8</Thickness>
<Style
x:Key="SettingsSectionHeaderTextBlockStyle"

View File

@@ -27,7 +27,6 @@
<!-- EmotionIcon -->
<x:String x:Key="UI_EmotionIcon25">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon25.png</x:String>
<x:String x:Key="UI_EmotionIcon52">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon52.png</x:String>
<x:String x:Key="UI_EmotionIcon71">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon71.png</x:String>
<x:String x:Key="UI_EmotionIcon250">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon250.png</x:String>
<x:String x:Key="UI_EmotionIcon271">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon271.png</x:String>

View File

@@ -2,11 +2,9 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Core.IO.Http.DynamicProxy;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Service;
using System.Globalization;
using System.Net.Http;
using System.Runtime.CompilerServices;
using Windows.Globalization;
@@ -43,7 +41,6 @@ internal static class DependencyInjection
serviceProvider.InitializeConsoleWindow();
serviceProvider.InitializeCulture();
serviceProvider.InitializedDynamicHttpProxy();
return serviceProvider;
}
@@ -51,10 +48,10 @@ internal static class DependencyInjection
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void InitializeCulture(this IServiceProvider serviceProvider)
{
CultureOptions cultureOptions = serviceProvider.GetRequiredService<CultureOptions>();
cultureOptions.SystemCulture = CultureInfo.CurrentCulture;
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
appOptions.PreviousCulture = CultureInfo.CurrentCulture;
CultureInfo cultureInfo = cultureOptions.CurrentCulture;
CultureInfo cultureInfo = appOptions.CurrentCulture;
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
@@ -70,9 +67,4 @@ internal static class DependencyInjection
{
_ = serviceProvider.GetRequiredService<ConsoleWindowLifeTime>();
}
private static void InitializedDynamicHttpProxy(this IServiceProvider serviceProvider)
{
HttpClient.DefaultProxy = serviceProvider.GetRequiredService<DynamicHttpProxy>();
}
}

View File

@@ -38,8 +38,8 @@ internal static class IocConfiguration
private static void AddDbContextCore(IServiceProvider provider, DbContextOptionsBuilder builder)
{
RuntimeOptions runtimeOptions = provider.GetRequiredService<RuntimeOptions>();
string dbFile = System.IO.Path.Combine(runtimeOptions.DataFolder, "Userdata.db");
RuntimeOptions hutaoOptions = provider.GetRequiredService<RuntimeOptions>();
string dbFile = System.IO.Path.Combine(hutaoOptions.DataFolder, "Userdata.db");
string sqlConnectionString = $"Data Source={dbFile}";
// Temporarily create a context

View File

@@ -29,10 +29,10 @@ internal static partial class IocHttpClientConfiguration
/// <param name="client">配置后的客户端</param>
private static void DefaultConfiguration(IServiceProvider serviceProvider, HttpClient client)
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(runtimeOptions.UserAgent);
client.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
}
/// <summary>

View File

@@ -1,106 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Win32.Registry;
using System.Net;
using System.Reflection;
namespace Snap.Hutao.Core.IO.Http.DynamicProxy;
[Injection(InjectAs.Singleton)]
internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, IDisposable
{
private const string ProxySettingPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections";
private static readonly MethodInfo ConstructSystemProxyMethod;
private readonly RegistryWatcher watcher;
private IWebProxy innerProxy = default!;
static DynamicHttpProxy()
{
Type? systemProxyInfoType = typeof(System.Net.Http.SocketsHttpHandler).Assembly.GetType("System.Net.Http.SystemProxyInfo");
ArgumentNullException.ThrowIfNull(systemProxyInfoType);
MethodInfo? constructSystemProxyMethod = systemProxyInfoType.GetMethod("ConstructSystemProxy", BindingFlags.Static | BindingFlags.Public);
ArgumentNullException.ThrowIfNull(constructSystemProxyMethod);
ConstructSystemProxyMethod = constructSystemProxyMethod;
}
public DynamicHttpProxy()
{
UpdateProxy();
watcher = new(ProxySettingPath, OnProxyChanged);
watcher.Start();
}
/// <inheritdoc/>
public ICredentials? Credentials
{
get => InnerProxy.Credentials;
set => InnerProxy.Credentials = value;
}
public string CurrentProxy
{
get
{
Uri? proxyUri = GetProxy("https://hut.ao".ToUri());
return proxyUri is null
? SH.ViewPageFeedbackCurrentProxyNoProxyDescription
: proxyUri.AbsoluteUri;
}
}
private IWebProxy InnerProxy
{
get => innerProxy;
[MemberNotNull(nameof(innerProxy))]
set
{
if (ReferenceEquals(innerProxy, value))
{
return;
}
(innerProxy as IDisposable)?.Dispose();
innerProxy = value;
}
}
public Uri? GetProxy(Uri destination)
{
return InnerProxy.GetProxy(destination);
}
public bool IsBypassed(Uri host)
{
return InnerProxy.IsBypassed(host);
}
public void Dispose()
{
(innerProxy as IDisposable)?.Dispose();
watcher.Dispose();
}
public void OnProxyChanged()
{
UpdateProxy();
Ioc.Default.GetRequiredService<ITaskContext>().InvokeOnMainThread(() => OnPropertyChanged(nameof(CurrentProxy)));
}
[MemberNotNull(nameof(innerProxy))]
private void UpdateProxy()
{
IWebProxy? proxy = ConstructSystemProxyMethod.Invoke(default, default) as IWebProxy;
ArgumentNullException.ThrowIfNull(proxy);
InnerProxy = proxy;
}
}

View File

@@ -11,14 +11,11 @@ namespace Snap.Hutao.Core.IO.Ini;
[HighQuality]
internal static class IniSerializer
{
public static List<IniElement> DeserializeFromFile(string filePath)
{
using (FileStream readStream = File.OpenRead(filePath))
{
return Deserialize(readStream);
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="fileStream">文件流</param>
/// <returns>Ini 元素集合</returns>
public static List<IniElement> Deserialize(FileStream fileStream)
{
List<IniElement> results = [];
@@ -53,14 +50,11 @@ internal static class IniSerializer
return results;
}
public static void SerializeToFile(string filePath, IEnumerable<IniElement> elements)
{
using (FileStream writeStream = File.Create(filePath))
{
Serialize(writeStream, elements);
}
}
/// <summary>
/// 序列化
/// </summary>
/// <param name="fileStream">写入的流</param>
/// <param name="elements">元素</param>
public static void Serialize(FileStream fileStream, IEnumerable<IniElement> elements)
{
using (StreamWriter writer = new(fileStream))

View File

@@ -69,9 +69,4 @@ internal static class StructMarshal
{
return new(point.X, point.Y, size.Width, size.Height);
}
public static SizeInt32 SizeInt32(RectInt32 rect)
{
return new(rect.Width, rect.Height);
}
}

View File

@@ -8,12 +8,12 @@ internal readonly struct Delay
/// <summary>
/// 随机延迟
/// </summary>
/// <param name="min">最小,闭</param>
/// <param name="max">最小,开</param>
/// <param name="minMilliSeconds">最小,闭</param>
/// <param name="maxMilliSeconds">最小,开</param>
/// <returns>任务</returns>
public static ValueTask RandomMilliSeconds(int min, int max)
public static ValueTask Random(int minMilliSeconds, int maxMilliSeconds)
{
return Task.Delay((int)(System.Random.Shared.NextDouble() * (max - min)) + min).AsValueTask();
return Task.Delay((int)(System.Random.Shared.NextDouble() * (maxMilliSeconds - minMilliSeconds)) + minMilliSeconds).AsValueTask();
}
public static ValueTask FromSeconds(int seconds)

View File

@@ -1,67 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Windows.UI;
namespace Snap.Hutao.Core.Windowing.Backdrop;
internal sealed class TransparentBackdrop : SystemBackdrop, IDisposable, IBackdropNeedEraseBackground
{
private readonly object compositorLock = new();
private Color tintColor;
private Windows.UI.Composition.CompositionColorBrush? brush;
private Windows.UI.Composition.Compositor? compositor;
public TransparentBackdrop()
: this(Colors.Transparent)
{
}
public TransparentBackdrop(Color tintColor)
{
this.tintColor = tintColor;
}
internal Windows.UI.Composition.Compositor Compositor
{
get
{
if (compositor is null)
{
lock (compositorLock)
{
if (compositor is null)
{
DispatcherQueue.EnsureSystemDispatcherQueue();
compositor = new Windows.UI.Composition.Compositor();
}
}
}
return compositor;
}
}
public void Dispose()
{
compositor?.Dispose();
}
protected override void OnTargetConnected(ICompositionSupportsSystemBackdrop connectedTarget, XamlRoot xamlRoot)
{
brush ??= Compositor.CreateColorBrush(tintColor);
connectedTarget.SystemBackdrop = brush;
}
protected override void OnTargetDisconnected(ICompositionSupportsSystemBackdrop disconnectedTarget)
{
disconnectedTarget.SystemBackdrop = null;
}
}
internal interface IBackdropNeedEraseBackground;

View File

@@ -9,8 +9,6 @@ namespace Snap.Hutao.Core.Windowing;
[HighQuality]
internal enum BackdropType
{
Transparent = -1,
/// <summary>
/// 无
/// </summary>

View File

@@ -9,7 +9,6 @@ using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service;
using System.Diagnostics;
using System.IO;
using Windows.Graphics;
using Windows.UI;
@@ -54,10 +53,10 @@ internal sealed class WindowController
private void InitializeCore()
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
window.AppWindow.Title = SH.FormatAppNameAndVersion(runtimeOptions.Version);
window.AppWindow.SetIcon(Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"));
window.AppWindow.Title = SH.FormatAppNameAndVersion(hutaoOptions.Version);
window.AppWindow.SetIcon(Path.Combine(hutaoOptions.InstalledLocation, "Assets/Logo.ico"));
ExtendsContentIntoTitleBar();
RecoverOrInitWindowSize();
@@ -158,7 +157,6 @@ internal sealed class WindowController
{
window.SystemBackdrop = backdropType switch
{
BackdropType.Transparent => new Backdrop.TransparentBackdrop(),
BackdropType.MicaAlt => new MicaBackdrop() { Kind = MicaKind.BaseAlt },
BackdropType.Mica => new MicaBackdrop() { Kind = MicaKind.Base },
BackdropType.Acrylic => new DesktopAcrylicBackdrop(),

View File

@@ -3,10 +3,6 @@
using Microsoft.UI.Xaml;
using System.Runtime.CompilerServices;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using WinRT.Interop;
using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Core.Windowing;
@@ -20,12 +16,4 @@ internal static class WindowExtension
WindowController windowController = new(window, window.WindowOptions, serviceProvider);
WindowControllers.Add(window, windowController);
}
public static void SetLayeredWindow(this Window window)
{
HWND hwnd = (HWND)WindowNative.GetWindowHandle(window);
nint style = GetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
style |= (nint)WINDOW_EX_STYLE.WS_EX_LAYERED;
SetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, style);
}
}

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Windowing.Backdrop;
using Snap.Hutao.Core.Windowing.HotKey;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Shell;
@@ -111,16 +110,6 @@ internal sealed class WindowSubclass : IDisposable
hotKeyController.OnHotKeyPressed(*(HotKeyParameter*)&lParam);
break;
}
case WM_ERASEBKGND:
{
if (window.SystemBackdrop is IBackdropNeedEraseBackground)
{
return (LRESULT)(int)(BOOL)true;
}
break;
}
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);

View File

@@ -1,19 +0,0 @@
<Window
x:Class="Snap.Hutao.IdentifyMonitorWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
mc:Ignorable="d">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="3">
<TextBlock Text="{shcm:ResourceString Name=WindowIdentifyMonitorHeader}"/>
<TextBlock
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{x:Bind Monitor}"
TextAlignment="Center"/>
</StackPanel>
</Window>

View File

@@ -1,30 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Snap.Hutao.Core;
using Windows.Graphics;
namespace Snap.Hutao;
internal sealed partial class IdentifyMonitorWindow : Window
{
public IdentifyMonitorWindow(DisplayArea displayArea, int index)
{
InitializeComponent();
Monitor = $"{displayArea.DisplayId.Value:X8}:{index}";
OverlappedPresenter presenter = OverlappedPresenter.Create();
presenter.SetBorderAndTitleBar(false, false);
presenter.IsAlwaysOnTop = true;
presenter.IsResizable = false;
AppWindow.SetPresenter(presenter);
PointInt32 point = new(40, 32);
SizeInt32 size = StructMarshal.SizeInt32(displayArea.WorkArea).Scale(0.1);
AppWindow.MoveAndResize(StructMarshal.RectInt32(point, size), displayArea);
}
public string Monitor { get; private set; }
}

View File

@@ -11,12 +11,6 @@ internal static class CollectionsNameValue
return [.. Enum.GetValues<TEnum>().Select(x => new NameValue<TEnum>(x.ToString(), x))];
}
public static List<NameValue<TEnum>> FromEnum<TEnum>(Func<TEnum, bool> codiction)
where TEnum : struct, Enum
{
return [.. Enum.GetValues<TEnum>().Where(codiction).Select(x => new NameValue<TEnum>(x.ToString(), x))];
}
public static List<NameValue<TSource>> From<TSource>(IEnumerable<TSource> sources, Func<TSource, string> nameSelector)
{
return [.. sources.Select(x => new NameValue<TSource>(nameSelector(x), x))];

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Core;
using Snap.Hutao.Core.Abstraction;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Web.Hoyolab;
@@ -13,7 +12,7 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
/// UIGF格式的信息
/// </summary>
[HighQuality]
internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, CultureOptions, string>
internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, MetadataOptions, string>
{
/// <summary>
/// 用户Uid
@@ -66,12 +65,12 @@ internal sealed class UIGFInfo : IMappingFrom<UIGFInfo, RuntimeOptions, CultureO
[JsonPropertyName("region_time_zone")]
public int? RegionTimeZone { get; set; } = default!;
public static UIGFInfo From(RuntimeOptions runtimeOptions, CultureOptions cultureOptions, string uid)
public static UIGFInfo From(RuntimeOptions runtimeOptions, MetadataOptions metadataOptions, string uid)
{
return new()
{
Uid = uid,
Language = cultureOptions.LanguageCode,
Language = metadataOptions.LanguageCode,
ExportTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
ExportApp = SH.AppName,
ExportAppVersion = runtimeOptions.Version.ToString(),

View File

@@ -64,14 +64,14 @@ internal sealed class UIIFInfo
/// <returns>专用 UIGF 信息</returns>
public static UIIFInfo From(IServiceProvider serviceProvider, string uid)
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
return new()
{
Uid = uid,
ExportTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
ExportApp = SH.AppName,
ExportAppVersion = runtimeOptions.Version.ToString(),
ExportAppVersion = hutaoOptions.Version.ToString(),
UIIFVersion = UIIF.CurrentVersion,
};
}

View File

@@ -247,7 +247,7 @@
<value>Not refreshed</value>
</data>
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
<value>Refreshed at {0:MM.dd HH:mm:ss}</value>
<value>Refresh at {0:MM.dd HH:mm:ss}</value>
</data>
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
<value>Schedule {0}</value>
@@ -738,7 +738,7 @@
<value>Avatar Calculator: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>My Character: Not Refreshed</value>
<value>My Characters: N/A</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>My Characters: {0:MM-dd HH:mm}</value>
@@ -870,23 +870,11 @@
<value>No writing permission in file system, unable to start the server conversion.</value>
</data>
<data name="ServiceGameEnsureGameResourceQueryResourceInformation" xml:space="preserve">
<value>Download game resource index</value>
<value>Querying Game Resource Information</value>
</data>
<data name="ServiceGameFileOperationExceptionMessage" xml:space="preserve">
<value>Failed to operate on game file: {0}</value>
</data>
<data name="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>Failed to unlock frame rate limit</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>Game in process</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>Select Game Path</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>Failed to download game resource index: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>Game process closed</value>
</data>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>Scan the QR code with MiHoYo BBS App</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>To avoid enable in a mistake, please input &lt;b&gt;title name&lt;/b&gt; of feature you are enabling</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>You are Enabling a Dangerous Feature</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>This action is irreversible, and all user login status will be lost</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>Set Cookie</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>Feedback Center</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>Wish History</value>
</data>
@@ -1389,7 +1368,7 @@
<value>This operation is irreversible. The achievement archive will be lost.</value>
</data>
<data name="ViewModelAchievementRemoveArchiveTitle" xml:space="preserve">
<value>Are you sure to delete archive {0}?</value>
<value>Are you sure you want to delete archive {0}?</value>
</data>
<data name="ViewModelAchievementUIAFExportPickerTitle" xml:space="preserve">
<value>Export UIAF Json file to the selected path</value>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>Convert server failed</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>Identify Monitors</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>Unable to read game config file: {0}, file may be not exist not lack of user permission</value>
</data>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>Failed to create desktop shortcut</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>You will need to re-download needed files, are you sure to delete?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>Delete Sever Conversion Client Cache</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>Used disk space: {0}</value>
</data>
@@ -1656,7 +1626,7 @@
<value>Create New Archive</value>
</data>
<data name="ViewPageAchievementAddArchiveHint" xml:space="preserve">
<value>Create New Archive to Continue</value>
<value>Create new archive to continue</value>
</data>
<data name="ViewPageAchievementExportLabel" xml:space="preserve">
<value>Export</value>
@@ -1677,7 +1647,7 @@
<value>Name, description, version or ID</value>
</data>
<data name="ViewPageAchievementSortIncompletedItemsFirst" xml:space="preserve">
<value>Prefer Incomplete</value>
<value>Prefer incomplete</value>
</data>
<data name="ViewPageAnnouncementActivity" xml:space="preserve">
<value>Event Notice</value>
@@ -1701,7 +1671,7 @@
<value>CRIT Rating</value>
</data>
<data name="ViewPageAvatarPropertyDefaultDescription" xml:space="preserve">
<value>No Character Data Fetched</value>
<value>No character data fetched</value>
</data>
<data name="ViewPageAvatarPropertyExportAsImage" xml:space="preserve">
<value>Export as Image</value>
@@ -1728,7 +1698,7 @@
<value>Sync character talents data</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>Sync from MiHoYo BBS My Character</value>
<value>Sync from MiHoYo BBS My Characters</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>Sync most data other than character talent</value>
@@ -1752,7 +1722,7 @@
<value>Create</value>
</data>
<data name="ViewPageCultivationAddProjectContinue" xml:space="preserve">
<value>Create Plan to Continue</value>
<value>Create plan to continue</value>
</data>
<data name="ViewPageCultivationAddProjectDescription" xml:space="preserve">
<value>You can add development plan items later from other pages</value>
@@ -1853,42 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>Verify Current User and Role</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>Search for questions and suggestions</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>Basic Information</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>Useful Links</value>
</data>
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
<value>Current Proxy</value>
</data>
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
<value>No Proxy</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>Keep in touch with us</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>Feature Documents</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>We always prioritize issues reported on GitHub</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>Development Roadmap</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>No Result</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>Snap Hutao Service Availability Monitor</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>Snap Hutao Services</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>Full Refresh</value>
</data>
@@ -1941,7 +1875,7 @@
<value>Input</value>
</data>
<data name="ViewPageGachaLogRecoverFromHutaoCloudDescription" xml:space="preserve">
<value>Recover Wish Records from Snap Hutao Cloud</value>
<value>Recover Wish Record from Snap Hutao Cloud</value>
</data>
<data name="ViewPageGachaLogRefresh" xml:space="preserve">
<value>Refresh</value>
@@ -2121,10 +2055,10 @@
<value>Borderless</value>
</data>
<data name="ViewPageLaunchGameAppearanceCloudThirdPartyMobileDescription" xml:space="preserve">
<value>Enable touchscreen layout, but the keyboard &amp; mouse are no longer usable</value>
<value>Enable touchscreen layout, but the keyboard &amp; mouse are no longer usable.</value>
</data>
<data name="ViewPageLaunchGameAppearanceExclusiveDescription" xml:space="preserve">
<value>Incompatible with embedded browsers; operations like switching window may cause the game to crash</value>
<value>Incompatible with embedded browsers; operations like switching window may cause the game to crash.</value>
</data>
<data name="ViewPageLaunchGameAppearanceExclusiveHeader" xml:space="preserve">
<value>Exclusive Fullscreen</value>
@@ -2154,7 +2088,7 @@
<value>Modify its default behavior at game startup</value>
</data>
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
<value>Launch Parameters</value>
<value>Start-up Arguments</value>
</data>
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
<value>General</value>
@@ -2208,7 +2142,7 @@
<value>Resource Download</value>
</data>
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
<value>Full Package</value>
<value>Client</value>
</data>
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
<value>Pre-download</value>
@@ -2258,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>Enabled</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>Take advantage of displays that support HDR for brighter, more vivid, and more detailed pictures</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>Enter your HoYoLab UID</value>
</data>
@@ -2277,7 +2205,7 @@
<value>Open Screenshots Folder</value>
</data>
<data name="ViewPageResetGamePathAction" xml:space="preserve">
<value>Select Game Path</value>
<value>Select game path</value>
</data>
<data name="ViewPageSettingAboutHeader" xml:space="preserve">
<value>About Snap Hutao</value>
@@ -2636,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>Debug Console</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>Cache file are downloaded for server conversion in Game Launcher</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>Delete Server Conversion Cache</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>Open Folder</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>Settings</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>
@@ -2742,7 +2661,7 @@
<value>Web Login</value>
</data>
<data name="ViewUserCookieOperationLoginQRCodeAction" xml:space="preserve">
<value>Login via QR code</value>
<value>Login via scanning QR code</value>
</data>
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
<value>Input Manually</value>
@@ -2828,9 +2747,6 @@
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>End in {0} hours</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>Failed to open clipboard</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>Copied to clipboard</value>
</data>
@@ -2895,10 +2811,10 @@
<value>{0} day</value>
</data>
<data name="WebDailyNoteResinRecoveryCompleted" xml:space="preserve">
<value>Original Resin is Full</value>
<value>Original Resin is full</value>
</data>
<data name="WebDailyNoteResinRecoveryFormat" xml:space="preserve">
<value>Will be Replenished in {0} {1:HH:mm}</value>
<value>Will be replenished in {0} {1:HH:mm}</value>
</data>
<data name="WebDailyNoteTransformerAppend" xml:space="preserve">
<value>Ready for use again after</value>
@@ -3011,7 +2927,4 @@
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{1}] network request exception in [{0}] please try again later</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>Monitor ID</value>
</data>
</root>

View File

@@ -121,7 +121,7 @@
<value>Snap Hutao Dev {0}</value>
</data>
<data name="AppElevatedDevNameAndVersion" xml:space="preserve">
<value>胡桃Dev {0} [管理员]</value>
<value>Snap Hutao Dev {0} [Administrator]</value>
</data>
<data name="AppElevatedNameAndVersion" xml:space="preserve">
<value>Snap Hutao {0} [Administrator]</value>
@@ -738,10 +738,10 @@
<value>Kalkulator Avatar: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>Karakter Saya: N/A</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩:{0:MM-dd HH:mm}</value>
<value>Karakter Saya: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>Enka: N/A</value>
@@ -870,23 +870,11 @@
<value>Tidak ada izin menulis dalam sistem berkas, tidak dapat memulai konversi server.</value>
</data>
<data name="ServiceGameEnsureGameResourceQueryResourceInformation" xml:space="preserve">
<value>Unduh indeks sumber daya game</value>
<value>Mencari Informasi Sumber Daya Game</value>
</data>
<data name="ServiceGameFileOperationExceptionMessage" xml:space="preserve">
<value>Gagal melakukan operasi pada file game: {0}</value>
</data>
<data name="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>Gagal membuka batas frame rate</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>Proses game sedang berjalan</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>Mohon pilih path game</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>Gagal mengunduh indeks sumber daya game: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>Proses game ditutup</value>
</data>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>Pindai kode QR dengan Aplikasi MiHoYo BBS</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>Anda Mengaktifkan Fitur Berbahaya</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>Tindakan ini tidak dapat dibatalkan, dan semua status login pengguna akan hilang.</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>Setel Cookie</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>Pusat Umpan Balik</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>Riwayat Wish</value>
</data>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>Konversi server gagal</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>Identifikasi Monitor</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>Tidak dapat membaca file konfigurasi game: {0}, file mungkin tidak ada atau kurang izin pengguna</value>
</data>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>Gagal membuat shortcut di desktop</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>Anda akan diminta mengunduh file yang diperlukan, Yakin ingin menghapus?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>Menghapus Cache Server Konfersi</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>Ruang disk yang digunakan: {0}</value>
</data>
@@ -1728,7 +1698,7 @@
<value>Sinkronisasi Data Talenta Karakter</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>Sinkronkan dari Karakter Saya MiHoYo BBS</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>Sinkronkan sebagian besar data kecuali talent karakter.</value>
@@ -1853,36 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>Verifikasi Pengguna dan Role Saat Ini</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>Cari pertanyaan dan saran</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>Informasi Dasar</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>Tautan Berguna</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>Tetap berhubungan dengan kami</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>Dokumen Fitur</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>Roadmap Pengembangan</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>Pemantau Ketersediaan Layanan Snap Hutao</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>Servis Snap Hutao</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>Segarkan Seutuhnya</value>
</data>
@@ -2252,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>Aktifkan</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>Manfaatkan tampilan yang mendukung rentang dinamis tinggi untuk gambar yang lebih terang, lebih jelas, dan lebih detail</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>Masukkan UID HoYoLab Anda</value>
</data>
@@ -2630,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>Konsol debug</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>File Cache diunduh untuk Server Konfersi pada Game Launcher</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>Menghapus Cache Server Konfersi</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>Buka berkas</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>Pengaturan</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>Rasio Penampilan Karakter = Penampilan Karakter di Lantai Ini (hanya dihitung sekali jika berulang) / Total Jumlah Rekor Abyss di Lantai Ini</value>
</data>
@@ -2822,9 +2747,6 @@
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>Selesai {0} jam</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>Gagal membuka clipboard</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>Disalin ke clipboard</value>
</data>
@@ -2925,7 +2847,7 @@
<value>{0} detik</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>Verifikasi gagal. Silakan periksa MiHoYo BBS - Karakter Saya - Catatan Realtime secara manual.</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>Format UID Salah</value>
@@ -2994,7 +2916,7 @@
<value>Server Snap Hutao sedang dalam perbaikan</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩」页面查看</value>
<value>Verifikasi gagal. Harap verifikasi secara manual atau periksa halaman Karakter Saya di MiHoYo BBS.</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>Kode Kembali: {0} | Pesan: {1}</value>
@@ -3005,7 +2927,4 @@
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{1}] pengecualian permintaan jaringan di [{0}], harap coba lagi nanti</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>ID Monitor</value>
</data>
</root>

View File

@@ -738,10 +738,10 @@
<value>育成計算: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>所持キャラ:未更新</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩{0:MM-dd HH:mm}</value>
<value>所持キャラ{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>キャラクターラインナップ:未更新</value>
@@ -870,23 +870,11 @@
<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="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>解锁帧率上限失败</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>游戏进程运行中</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>请选择游戏路径</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>下载游戏资源索引失败: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>ゲームプロセスが終了しました</value>
</data>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>MiHoYo BBS を使用して QR コードをスキャンします</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>你正在启用一个危险功能</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>この操作は取り消せません。すべてのユーザーのログイン状態が解除されます。</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>クッキーを設定</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>反馈中心</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>祈願履歴</value>
</data>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>サーバーの切り替えができませんでした</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>识别显示器</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>ゲーム設定ファイル {0} の読み込みに失敗しました。ファイルが無いか、権限が不足している可能性があります。</value>
</data>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>デスクトップへのショートカット作成に失敗しました</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>后续转换会重新下载所需的文件,确定要删除吗?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>删除转换服务器游戏客户端缓存</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>使用済みディスク容量: {0}</value>
</data>
@@ -1728,7 +1698,7 @@
<value>キャラクターの天賦情報を同期</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>MiHoYo BBSから所持キャラを同期</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>キャラ天賦以外の情報を概ね同期</value>
@@ -1853,36 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>現在のユーザーとUIDを確認する</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>搜索问题与建议</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>基本信息</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>常用链接</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>与我们密切联系</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>功能指南</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>开发路线规划</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>胡桃服务可用性监控</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>胡桃服务</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>すべて更新</value>
</data>
@@ -2252,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>有効</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>HDRをサポートするディスプレイを活用して、より明るく鮮やかなグラフィックを実現します。</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>HoYoLab UIDを入力してください</value>
</data>
@@ -2630,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>デバッグコンソール</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>在启动游戏中转换服务器后会产生对应的游戏客户端文件用作缓存</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>删除转换服务器缓存</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>フォルダを開く</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>设置</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>キャラクター出場率 = この階層における出場回数(最初の一回のみカウント) / この階層のアップロード総数</value>
</data>
@@ -2822,9 +2747,6 @@
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>{0} 時間後に終了</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>打开剪贴板失败</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>クリップボードにコピーしました。</value>
</data>
@@ -2925,7 +2847,7 @@
<value>{0} 秒</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>認証に失敗しました。「MiHoYo BBS - 戦績ツール - リアルタイムノート」で確認し、認証を行ってください</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>UIDは正しくありません</value>
@@ -2994,7 +2916,7 @@
<value>胡桃サーバがメンテナンス中です</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩」页面查看</value>
<value>認証に失敗しました。 手動で認証するか、MiHoYo BBS - 戦績 を確認してください。</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>リターンコード:{0} | メッセージ:{1}</value>
@@ -3005,7 +2927,4 @@
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{0}] の[{1}] のリクエストにエラーが発生、時間をおいてから試してください</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>显示器编号</value>
</data>
</root>

View File

@@ -738,10 +738,10 @@
<value>养成计算:{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>我的角色:尚未刷新</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩{0:MM-dd HH:mm}</value>
<value>我的角色{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>角色橱窗:尚未刷新</value>
@@ -870,23 +870,11 @@
<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="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>解锁帧率上限失败</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>游戏进程运行中</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>请选择游戏路径</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>下载游戏资源索引失败: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>游戏进程已退出</value>
</data>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>使用米游社扫描二维码</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>你正在启用一个危险功能</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>이 작업은 되돌릴 수 없으며, 모든 사용자 로그인 상태가 해제됩니다</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>쿠키 설정</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>反馈中心</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>기원 기록</value>
</data>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>서버 변경 실패</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>识别显示器</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>创建桌面快捷方式失败</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>后续转换会重新下载所需的文件,确定要删除吗?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>删除转换服务器游戏客户端缓存</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>已使用磁盘空间:{0}</value>
</data>
@@ -1728,7 +1698,7 @@
<value>캐릭터 특성 정보 동기화</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>HoYoLAB에서 내 캐릭터 동기화</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>캐릭터 특성을 제외한 대부분의 정보 동기화</value>
@@ -1853,36 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>현재 사용자와 캐릭터 확인</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>搜索问题与建议</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>基本信息</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>常用链接</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>与我们密切联系</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>功能指南</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>开发路线规划</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>胡桃服务可用性监控</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>胡桃服务</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>전체 동기화</value>
</data>
@@ -2252,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>활성화</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>充分利用支持高动态范围的显示器获得更亮、更生动、更精细的画面</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>HoYoLab Uid를 입력하세요</value>
</data>
@@ -2630,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>调试控制台</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>在启动游戏中转换服务器后会产生对应的游戏客户端文件用作缓存</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>删除转换服务器缓存</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>打开文件夹</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>设置</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
@@ -2822,9 +2747,6 @@
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>{0}시간 후 종료</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>打开剪贴板失败</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>已复制到剪贴板</value>
</data>
@@ -2925,7 +2847,7 @@
<value>{0}초</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>인증에 실패했습니다. 수동으로 인증하거나 'HoYoLAB-전적-실시간 메모' 페이지에서 확인하시기 바랍니다.</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>错误的 UID 格式</value>
@@ -2994,7 +2916,7 @@
<value>胡桃服务维护中</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩」页面查看</value>
<value>验证失败,请手动验证或前往「米游社-我的角色」页面查看</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>상태:{0} | 정보:{1}</value>
@@ -3005,7 +2927,4 @@
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>显示器编号</value>
</data>
</root>

View File

@@ -738,10 +738,10 @@
<value>养成计算:{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>我的角色:尚未刷新</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩{0:MM-dd HH:mm}</value>
<value>我的角色{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>角色橱窗:尚未刷新</value>
@@ -1284,7 +1284,7 @@
<value>使用米游社扫描二维码</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
<value>请输入正在启用的功能标题</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>你正在启用一个危险功能</value>
@@ -1310,9 +1310,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>设置 Cookie</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>反馈中心</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>祈愿记录</value>
</data>
@@ -1562,9 +1559,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>切换服务器失败</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>识别显示器</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
@@ -1728,7 +1722,7 @@
<value>同步角色天赋信息</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>从米游社我的角色同步</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>同步角色天赋外的大部分信息</value>
@@ -1853,42 +1847,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>验证当前用户与角色</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>搜索问题与建议</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>基本信息</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>常用链接</value>
</data>
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
<value>当前代理</value>
</data>
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
<value>无代理</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>与我们密切联系</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>功能指南</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>开发路线规划</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>胡桃服务可用性监控</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>胡桃服务</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>全量刷新</value>
</data>
@@ -2645,9 +2603,6 @@
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>打开文件夹</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>设置</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
@@ -2931,7 +2886,7 @@
<value>{0} 秒</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>验证失败,请手动验证或前往「米游社-我的角色-实时便笺」页面查看</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>错误的 UID 格式</value>
@@ -3000,7 +2955,7 @@
<value>胡桃服务维护中</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩」页面查看</value>
<value>验证失败,请手动验证或前往「米游社-我的角色」页面查看</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>状态:{0} | 信息:{1}</value>
@@ -3011,7 +2966,4 @@
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>显示器编号</value>
</data>
</root>

View File

@@ -510,141 +510,141 @@
<value>Необходимо войти в учетную запись miHoYo/HoYoLAB и выбрать пользователя с персонажем</value>
</data>
<data name="ServerGachaLogServiceDeleteEntrySucceed" xml:space="preserve">
<value>Удален Uid: {0} из {1} записи пожеланий</value>
<value>删除了 Uid{0} {1} 条祈愿记录</value>
</data>
<data name="ServerGachaLogServiceInsufficientRecordSlot" xml:space="preserve">
<value>Достигнуто максимально допустимое количество архивов истории желаний в облаке Snap Hutao</value>
<value>胡桃云保存的祈愿记录存档数已达当前账号上限</value>
</data>
<data name="ServerGachaLogServiceInsufficientTime" xml:space="preserve">
<value>Сервис загрузки записей пожеланий не активирован или истек срок его действия</value>
<value>未开通祈愿记录上传服务或已到期</value>
</data>
<data name="ServerGachaLogServiceInvalidGachaLogData" xml:space="preserve">
<value>Данные о желаниях содержат недопустимые предметы и не могут быть сохранены в Ху Тао облако</value>
<value>祈愿数据存在无效的物品,无法保存至胡桃云</value>
</data>
<data name="ServerGachaLogServiceServerDatabaseError" xml:space="preserve">
<value>Данные некорректны, не удается сохранить в облако. Пожалуйста, не загружайте через другие аккаунты или попробуйте удалить данные в облаке и повторите попытку</value>
<value>数据异常,无法保存至云端,请勿跨账号上传或尝试删除云端数据后重试</value>
</data>
<data name="ServerGachaLogServiceUploadEntrySucceed" xml:space="preserve">
<value>Загружено Uid: {0} из {1} записи желаний, Сохранено {2} записей</value>
<value>上传了 Uid{0} {1} 条祈愿记录,存储了 {2} 条</value>
</data>
<data name="ServerPassportLoginRequired" xml:space="preserve">
<value>Пожалуйста, сначала войдите или зарегистрируйтесь Snap Hutao аккаунт</value>
<value>请先登录或注册胡桃账号</value>
</data>
<data name="ServerPassportLoginSucceed" xml:space="preserve">
<value>Успешный вход</value>
<value>登录成功</value>
</data>
<data name="ServerPassportRegisterSucceed" xml:space="preserve">
<value>Регистрация успешна</value>
<value>注册成功</value>
</data>
<data name="ServerPassportResetPasswordSucceed" xml:space="preserve">
<value>Новый пароль установлен успешно</value>
<value>新密码设置成功</value>
</data>
<data name="ServerPassportServiceEmailHasNotRegistered" xml:space="preserve">
<value>Текущий адрес электронной почты еще не зарегистрирован</value>
<value>当前邮箱尚未注册</value>
</data>
<data name="ServerPassportServiceEmailHasRegistered" xml:space="preserve">
<value>Текущий адрес электронной почты уже зарегистрирован</value>
<value>当前邮箱已被注册</value>
</data>
<data name="ServerPassportServiceInternalException" xml:space="preserve">
<value>Ошибка регистрации, проблемы с сервером. Пожалуйста, свяжитесь с разработчиком для решения проблемы</value>
<value>注册失败,服务器异常,请尽快联系开发者解决</value>
</data>
<data name="ServerPassportServiceUnregisterFailed" xml:space="preserve">
<value>Пользователь не существует, отмена не удалась</value>
<value>用户不存在,注销失败</value>
</data>
<data name="ServerPassportUnregisterSucceed" xml:space="preserve">
<value>Пользователь успешно отменен</value>
<value>用户注销成功</value>
</data>
<data name="ServerPassportUserInfoNotExist" xml:space="preserve">
<value>Пользователь не существует, не удалось получить информацию о пользователе</value>
<value>用户不存在,获取用户信息失败</value>
</data>
<data name="ServerPassportUserNameOrPasswordIncorrect" xml:space="preserve">
<value>Неверное имя пользователя или пароль</value>
<value>用户名或密码错误</value>
</data>
<data name="ServerPassportVerifyFailed" xml:space="preserve">
<value>Проверка не удалась</value>
<value>验证失败</value>
</data>
<data name="ServerPassportVerifyRequestNotCurrentUser" xml:space="preserve">
<value>Ошибка проверки запроса, это не текущий вход в учетную запись</value>
<value>验证请求失败,不是当前登录的账号</value>
</data>
<data name="ServerPassportVerifyRequestSuccess" xml:space="preserve">
<value>Код подтверждения отправлен на электронную почту</value>
<value>验证码已发送至邮箱</value>
</data>
<data name="ServerPassportVerifyRequestUserAlreadyExisted" xml:space="preserve">
<value>Ошибка проверки запроса, текущий адрес электронной почты уже зарегистрирован</value>
<value>验证请求失败,当前邮箱已被注册</value>
</data>
<data name="ServerPassportVerifyTooFrequent" xml:space="preserve">
<value>Слишком частые запросы проверки, пожалуйста, повторите через 1 минуту</value>
<value>验证请求过快,请 1 分钟后再试</value>
</data>
<data name="ServerRecordBannedUid" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, текущий Uid заблокирован в базе данных Walnut</value>
<value>上传深渊记录失败,当前 Uid 已被胡桃数据库封禁</value>
</data>
<data name="ServerRecordComputingStatistics" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, выполняется подсчет статистики</value>
<value>上传深渊记录失败,正在计算统计数据</value>
</data>
<data name="ServerRecordComputingStatistics2" xml:space="preserve">
<value>Не удалось получить данные, выполняется подсчет статистики</value>
<value>获取数据失败,正在计算统计数据</value>
</data>
<data name="ServerRecordInternalException" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, Сервер недоступен, пожалуйста, свяжитесь с разработчиком для решения проблемы</value>
<value>上传深渊记录失败,服务器异常,请尽快联系开发者解决</value>
</data>
<data name="ServerRecordInvalidData" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, обнаружены недопустимые данные</value>
<value>上传深渊记录失败,存在无效的数据</value>
</data>
<data name="ServerRecordInvalidUid" xml:space="preserve">
<value>Недопустимый Uid</value>
<value>无效的 Uid</value>
</data>
<data name="ServerRecordNotCurrentSchedule" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, это не текущие данные</value>
<value>上传深渊记录失败,不是本期数据</value>
</data>
<data name="ServerRecordPreviousRequestNotCompleted" xml:space="preserve">
<value>Не удалось загрузить записи из Бездны, записи для текущего Uid все еще обрабатываются. Пожалуйста, не повторяйте операцию</value>
<value>上传深渊记录失败,当前 Uid 的记录仍在处理中,请勿重复操作</value>
</data>
<data name="ServerRecordUploadSuccessAndGachaLogServiceTimeExtended" xml:space="preserve">
<value>Загрузка записей из Бездны успешна, выдан срок обслуживания загрузки записей о желаниях</value>
<value>上传深渊记录成功,获赠祈愿记录上传服务时长</value>
</data>
<data name="ServerRecordUploadSuccessButNoPassport" xml:space="preserve">
<value>Загрузка записей из Бездны успешна, Но без входа в учетную Snap Hutao пропускной билет, Невозможно получить бесплатный период обслуживания для загрузки записей о желаниях</value>
<value>上传深渊记录成功,但未登录胡桃通行证,无法获赠祈愿记录上传服务时长</value>
</data>
<data name="ServerRecordUploadSuccessButNoSuchUser" xml:space="preserve">
<value>Загрузка записей из Бездны успешна, Но не удается найти пользователя, Невозможно получить бесплатный период обслуживания для загрузки записей о желаниях</value>
<value>上传深渊记录成功,但无法找到用户,无法获赠祈愿记录上传服务时长</value>
</data>
<data name="ServerRecordUploadSuccessButNotFirstTimeAtCurrentSchedule" xml:space="preserve">
<value>Загрузка записей из Бездны успешна, Но это не первая подача в текущем периоде, Невозможно получить бесплатный период обслуживания для загрузки записей о желаниях</value>
<value>上传深渊记录成功,但不是本期首次提交,无法获赠祈愿记录上传服务时长</value>
</data>
<data name="ServiceAchievementImportResultFormat" xml:space="preserve">
<value>Добавить:{0} достижения | Обновление: {1} достижение | Удаление: {2} достижения</value>
<value>新增:{0} 个成就 | 更新:{1} 个成就 | 删除:{2} 个成就</value>
</data>
<data name="ServiceAchievementUIAFImportPickerFilterText" xml:space="preserve">
<value>UIAF Json файл</value>
<value>UIAF Json 文件</value>
</data>
<data name="ServiceAchievementUIAFImportPickerTitile" xml:space="preserve">
<value>Открыть UIAF Json файл</value>
<value>打开 UIAF Json 文件</value>
</data>
<data name="ServiceAchievementUserdataCorruptedInnerIdNotUnique" xml:space="preserve">
<value>В одном архиве достижений обнаружено несколько одинаковых идентификаторов достижений</value>
<value>单个成就存档内发现多个相同的成就 Id</value>
</data>
<data name="ServiceAvatarInfoPropertyAtk" xml:space="preserve">
<value>Сила атаки</value>
<value>攻击力</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyBaseAtk" xml:space="preserve">
<value>Базовая сила атаки</value>
<value>基础攻击力</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyBaseDef" xml:space="preserve">
<value>Основная защита</value>
<value>基础防御力</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyBaseHp" xml:space="preserve">
<value>Базовое здоровье</value>
<value>基础生命值</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyCDmg" xml:space="preserve">
<value>Урон при критическом ударе</value>
<value>暴击伤害</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyCE" xml:space="preserve">
<value>Эффективность заряда элемента</value>
<value>元素充能效率</value>
<comment>Need EXACT same string in game</comment>
</data>
<data name="ServiceAvatarInfoPropertyCR" xml:space="preserve">
@@ -738,10 +738,10 @@
<value>Калькулятор аватара: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>Мои персонажи: нет</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩:{0:MM-dd HH:mm}</value>
<value>Мои персонажи: {0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>Enka: N/A</value>
@@ -870,23 +870,11 @@
<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="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>解锁帧率上限失败</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>游戏进程运行中</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>请选择游戏路径</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>下载游戏资源索引失败: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>游戏进程已退出</value>
</data>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>使用米游社扫描二维码</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>你正在启用一个危险功能</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>该操作是不可逆的,所有用户登录状态会丢失</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>设置 Cookie</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>反馈中心</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>祈愿记录</value>
</data>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>切换服务器失败</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>识别显示器</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>无法读取游戏配置文件: {0},可能是文件不存在或权限不足</value>
</data>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>创建桌面快捷方式失败</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>后续转换会重新下载所需的文件,确定要删除吗?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>删除转换服务器游戏客户端缓存</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>已使用磁盘空间:{0}</value>
</data>
@@ -1728,7 +1698,7 @@
<value>同步角色天赋信息</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>从米游社我的角色同步</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>同步角色天赋外的大部分信息</value>
@@ -1853,36 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>验证当前用户与角色</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>搜索问题与建议</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>基本信息</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>常用链接</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>与我们密切联系</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>功能指南</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>开发路线规划</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>胡桃服务可用性监控</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>胡桃服务</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>全量刷新</value>
</data>
@@ -2252,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>启用</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>充分利用支持高动态范围的显示器获得更亮、更生动、更精细的画面</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>请输入你的 HoYoLab Uid</value>
</data>
@@ -2630,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>调试控制台</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>在启动游戏中转换服务器后会产生对应的游戏客户端文件用作缓存</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>删除转换服务器缓存</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>打开文件夹</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>设置</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
</data>
@@ -2808,204 +2733,198 @@
<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>\d\.\d版本更新说明</value>
</data>
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
<value>Начало через {0} дней</value>
<value>{0} 天后开始</value>
</data>
<data name="WebAnnouncementTimeDaysEndFormat" xml:space="preserve">
<value>Закончится через {0} дней</value>
<value>{0} 天后结束</value>
</data>
<data name="WebAnnouncementTimeHoursBeginFormat" xml:space="preserve">
<value>Начинается через {0} часов</value>
<value>{0} 小时后开始</value>
</data>
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>Закончится через {0} часов</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>Не удалось открыть буфер обмена</value>
<value>{0} 小时后结束</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>Скопировано в буфер обмена</value>
<value>已复制到剪贴板</value>
</data>
<data name="WebDailyNoteArchonQuestStatusFinished" xml:space="preserve">
<value>Завершенно</value>
<value>全部完成</value>
</data>
<data name="WebDailyNoteArchonQuestStatusNotOpen" xml:space="preserve">
<value>Недоступно</value>
<value>尚未开启</value>
</data>
<data name="WebDailyNoteArchonQuestStatusOngoing" xml:space="preserve">
<value>В процессе</value>
<value>进行中</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusFinishedNonReward" xml:space="preserve">
<value>Выполнено</value>
<value>已完成</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusForbid" xml:space="preserve">
<value>Forbid to Claim</value>
<value>禁止领取</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusInvalid" xml:space="preserve">
<value>Недействительно</value>
<value>无效</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusTakenAward" xml:space="preserve">
<value>Получено</value>
<value>已领取</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusUnfinished" xml:space="preserve">
<value>Незаконченно</value>
<value>尚未完成</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusWaitTaken" xml:space="preserve">
<value>Ready to claim</value>
<value>等待领取</value>
</data>
<data name="WebDailyNoteExpeditionRemainHoursFormat" xml:space="preserve">
<value>{0} часов</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteExpeditionRemainMinutesFormat" xml:space="preserve">
<value>{0} минут</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteExtraTaskRewardNotAllowed" xml:space="preserve">
<value>Incomplete Daily Commissions</value>
<value>今日完成委托数量不足</value>
</data>
<data name="WebDailyNoteExtraTaskRewardNotTaken" xml:space="preserve">
<value>Ежедневная награда не собрана</value>
<value>「每日委托」奖励未领取</value>
</data>
<data name="WebDailyNoteExtraTaskRewardReceived" xml:space="preserve">
<value>Ежедневная награда собрана</value>
<value>「每日委托」奖励已领取</value>
</data>
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
<value>Будет заполнен через {0} {1:HH:mm}</value>
<value>预计 {0} {1:HH:mm} 达到存储上限</value>
</data>
<data name="WebDailyNoteHomeLocked" xml:space="preserve">
<value>Serenitea Pot not Unlocked</value>
<value>尚未解锁洞天</value>
</data>
<data name="WebDailyNoteRecoveryTimeDay0" xml:space="preserve">
<value>Сегодня</value>
<value>今天</value>
</data>
<data name="WebDailyNoteRecoveryTimeDay1" xml:space="preserve">
<value>Завтра</value>
<value>明天</value>
</data>
<data name="WebDailyNoteRecoveryTimeDay2" xml:space="preserve">
<value>Послезавтра</value>
<value>后天</value>
</data>
<data name="WebDailyNoteRecoveryTimeDayFormat" xml:space="preserve">
<value>{0} день</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteResinRecoveryCompleted" xml:space="preserve">
<value>Смола заполнена</value>
<value>原粹树脂已完全恢复</value>
</data>
<data name="WebDailyNoteResinRecoveryFormat" xml:space="preserve">
<value>Будет пополнен через {0} {1:HH:mm}</value>
<value>将于 {0} {1:HH:mm} 后全部恢复</value>
</data>
<data name="WebDailyNoteTransformerAppend" xml:space="preserve">
<value>Снова готов к использованию после</value>
<value>后可再次使用</value>
</data>
<data name="WebDailyNoteTransformerDaysFormat" xml:space="preserve">
<value>{0} дней</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteTransformerHoursFormat" xml:space="preserve">
<value>{0} часов</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteTransformerMinutesFormat" xml:space="preserve">
<value>{0} минут</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteTransformerNotObtained" xml:space="preserve">
<value>Не получен</value>
<value>尚未获得</value>
</data>
<data name="WebDailyNoteTransformerNotObtainedDetail" xml:space="preserve">
<value>Transformer not obtained</value>
<value>尚未获得参量质变仪</value>
</data>
<data name="WebDailyNoteTransformerNotReached" xml:space="preserve">
<value>Перезарядка</value>
<value>冷却中</value>
</data>
<data name="WebDailyNoteTransformerReached" xml:space="preserve">
<value>Разрешить</value>
<value>可使用</value>
</data>
<data name="WebDailyNoteTransformerReady" xml:space="preserve">
<value>Готов</value>
<value>已准备完成</value>
</data>
<data name="WebDailyNoteTransformerSecondsFormat" xml:space="preserve">
<value>{0} Секунд</value>
<value>{0} </value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>验证失败,请手动验证或前往「米游社-我的角色-实时便笺」页面查看</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>Неправильный формат UID</value>
<value>错误的 UID 格式</value>
</data>
<data name="WebEnkaResponseStatusCode404" xml:space="preserve">
<value>Идентификатор UID не существует, пожалуйста, повторите попытку позже</value>
<value>角色 UID 不存在,请稍候再试</value>
</data>
<data name="WebEnkaResponseStatusCode424" xml:space="preserve">
<value>Игра на обновлении</value>
<value>游戏维护中</value>
</data>
<data name="WebEnkaResponseStatusCode429" xml:space="preserve">
<value>Слишком много запросов, пожалуйста, повторите попытку позже</value>
<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>
<value>角色活动祈愿</value>
</data>
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
<value>Молитва события персонажа - 2</value>
<value>角色活动祈愿-2</value>
</data>
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
<value>Молитва новичка</value>
<value>新手祈愿</value>
</data>
<data name="WebGachaConfigTypePermanentWish" xml:space="preserve">
<value>Стандартная молитва</value>
<value>常驻祈愿</value>
</data>
<data name="WebGachaConfigTypeWeaponEventWish" xml:space="preserve">
<value>Молитва события оружия</value>
<value>武器活动祈愿</value>
</data>
<data name="WebGameResourcePathCopySucceed" xml:space="preserve">
<value>Ссылка успешно скопирована</value>
<value>下载链接复制成功</value>
</data>
<data name="WebHoyolabInvalidRegion" xml:space="preserve">
<value>Ошибка сервера</value>
<value>无效的服务器</value>
</data>
<data name="WebHoyolabInvalidUid" xml:space="preserve">
<value>Invalid UID</value>
<value>无效的 UID</value>
</data>
<data name="WebHoyolabRegionCNGF01" xml:space="preserve">
<value>CN Server: Official</value>
<value>国服 官方服</value>
</data>
<data name="WebHoyolabRegionCNQD01" xml:space="preserve">
<value>CN Server: bilibili</value>
<value>国服 渠道服</value>
</data>
<data name="WebHoyolabRegionOSASIA" xml:space="preserve">
<value>Oversea Server: Asian</value>
<value>国际服 亚服</value>
</data>
<data name="WebHoyolabRegionOSCHT" xml:space="preserve">
<value>Oversea Server: TW/HK/MU server</value>
<value>国际服 港澳台服</value>
</data>
<data name="WebHoyolabRegionOSEURO" xml:space="preserve">
<value>Oversea Server: EU</value>
<value>国际服 欧服</value>
</data>
<data name="WebHoyolabRegionOSUSA" xml:space="preserve">
<value>Oversea Server: NA</value>
<value>国际服 美服</value>
</data>
<data name="WebHutaoServiceUnAvailable" xml:space="preserve">
<value>Сервер Snap Hutao находится на техническом обслуживании</value>
<value>胡桃服务维护中</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩」页面查看</value>
<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>
<value>请刷新 Cookie原始消息{0}</value>
</data>
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{1}] исключение сетевого запроса в [{0}] пожалуйста, повторите попытку позже</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>显示器编号</value>
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
</data>
</root>

View File

@@ -124,7 +124,7 @@
<value>胡桃Dev {0} [管理员]</value>
</data>
<data name="AppElevatedNameAndVersion" xml:space="preserve">
<value>胡桃 {0} [系統管理]</value>
<value>胡桃 {0} [管理]</value>
</data>
<data name="AppName" xml:space="preserve">
<value>胡桃</value>
@@ -148,7 +148,7 @@
<value>無效的 Uri</value>
</data>
<data name="ControlImageCompositionImageHttpRequest" xml:space="preserve">
<value>HTTP GET {0}</value>
<value>获取HTTP{0}</value>
</data>
<data name="ControlImageCompositionImageSystemException" xml:space="preserve">
<value>應用 CompositionImage 的源時發生異常</value>
@@ -196,7 +196,7 @@
<value>歡迎使用胡桃</value>
</data>
<data name="LaunchGameTitle" xml:space="preserve">
<value>選擇號並動</value>
<value>選擇號並動</value>
</data>
<data name="ModelBindingAvatarPropertyWeaponAffixFormat" xml:space="preserve">
<value>精煉 {0}</value>
@@ -738,10 +738,10 @@
<value>養成計算:{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
<value>原神战绩:尚未刷新</value>
<value>我的角色:尚未重新整理</value>
</data>
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
<value>原神战绩{0:MM-dd HH:mm}</value>
<value>我的角色{0:MM-dd HH:mm}</value>
</data>
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
<value>角色櫥窗:尚未刷新</value>
@@ -870,23 +870,11 @@
<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="ServiceGameLaunchExecutionGameFpsUnlockFailed" xml:space="preserve">
<value>解鎖 FPS 上限失敗</value>
</data>
<data name="ServiceGameLaunchExecutionGameIsRunning" xml:space="preserve">
<value>遊戲進程運行中</value>
</data>
<data name="ServiceGameLaunchExecutionGamePathNotValid" xml:space="preserve">
<value>請選擇遊戲路徑</value>
</data>
<data name="ServiceGameLaunchExecutionGameResourceQueryIndexFailed" xml:space="preserve">
<value>下载游戏资源索引失败: {0}</value>
</data>
<data name="ServiceGameLaunchPhaseProcessExited" xml:space="preserve">
<value>遊戲進程已退出</value>
</data>
@@ -897,13 +885,13 @@
<value>遊戲進程已啟動</value>
</data>
<data name="ServiceGameLaunchPhaseUnlockFpsFailed" xml:space="preserve">
<value>解鎖 FPS 上限失敗,正在結束遊戲程</value>
<value>解鎖幀率上限失敗,正在結束遊戲程</value>
</data>
<data name="ServiceGameLaunchPhaseUnlockFpsSucceed" xml:space="preserve">
<value>解鎖 FPS 上限成功</value>
<value>解鎖幀率上限成功</value>
</data>
<data name="ServiceGameLaunchPhaseUnlockingFps" xml:space="preserve">
<value>正在嘗試解鎖 FPS 上限</value>
<value>正在嘗試解鎖幀率上限</value>
</data>
<data name="ServiceGameLaunchPhaseWaitingProcessExit" xml:space="preserve">
<value>等待遊戲進程退出</value>
@@ -1283,12 +1271,6 @@
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
<value>使用米遊社掃描 QR 碼</value>
</data>
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
<value>为防止你在无意间启用,请输入正在启用的功能开关的&lt;b&gt;标题名称&lt;/b&gt;</value>
</data>
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
<value>你正在啟用一個危險功能</value>
</data>
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
<value>該操作是不可逆,所有用戶登錄狀態會遺失</value>
</data>
@@ -1310,9 +1292,6 @@
<data name="ViewDialogUserTitle" xml:space="preserve">
<value>設定 Cookie</value>
</data>
<data name="ViewFeedbackHeader" xml:space="preserve">
<value>回饋中心</value>
</data>
<data name="ViewGachaLogHeader" xml:space="preserve">
<value>祈願記錄</value>
</data>
@@ -1562,9 +1541,6 @@
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
<value>切換伺服器失敗</value>
</data>
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
<value>識別顯示器</value>
</data>
<data name="ViewModelLaunchGameMultiChannelReadFail" xml:space="preserve">
<value>無法讀取遊戲設定檔案: {0},可能是檔案不存在或權限不足</value>
</data>
@@ -1578,7 +1554,7 @@
<value>切換帳號失敗</value>
</data>
<data name="ViewModelLaunchGameUnableToSwitchUidAttachedGameAccount" xml:space="preserve">
<value>無法選擇 UID [{0}] 對應的帳號 [{1}]該帳號不屬於當前伺服器</value>
<value>无法选择UID [{0}] 对应的账号 [{1}]该账号不属于当前服务器</value>
</data>
<data name="ViewModelSettingActionComplete" xml:space="preserve">
<value>操作完成</value>
@@ -1598,12 +1574,6 @@
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>創建桌面捷徑失敗</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderContent" xml:space="preserve">
<value>後續轉換會重新下載所需檔案,確定要刪除嗎?</value>
</data>
<data name="ViewModelSettingDeleteServerCacheFolderTitle" xml:space="preserve">
<value>刪除轉換伺服器遊戲用戶端暫存</value>
</data>
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
<value>已使用磁碟空間:{0}</value>
</data>
@@ -1686,7 +1656,7 @@
<value>遊戲公告</value>
</data>
<data name="ViewPageAnnouncementViewDetails" xml:space="preserve">
<value>檢視詳情</value>
<value>查看详情</value>
</data>
<data name="ViewPageAvatarPropertyArtifactScore" xml:space="preserve">
<value>聖遺物評分</value>
@@ -1728,7 +1698,7 @@
<value>同步角色天賦信息</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
<value>从米游社原神战绩同步</value>
<value>從 HoYoLAB - 戰績中同步</value>
</data>
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
<value>同步角色天賦外的大部分信息</value>
@@ -1853,36 +1823,6 @@
<data name="ViewPageDailyNoteVerify" xml:space="preserve">
<value>驗證當前用戶與角色</value>
</data>
<data name="ViewPageFeedbackAutoSuggestBoxPlaceholder" xml:space="preserve">
<value>搜尋問題與建議</value>
</data>
<data name="ViewPageFeedBackBasicInformation" xml:space="preserve">
<value>基本資訊</value>
</data>
<data name="ViewPageFeedbackCommonLinksHeader" xml:space="preserve">
<value>常用链接</value>
</data>
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
<value>与我们密切联系</value>
</data>
<data name="ViewPageFeedbackFeatureGuideHeader" xml:space="preserve">
<value>功能指南</value>
</data>
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
<value>我们总是优先处理 GitHub 上的问题</value>
</data>
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
<value>开发路线规划</value>
</data>
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
<value>暂无搜索结果</value>
</data>
<data name="ViewPageFeedbackServerStatusDescription" xml:space="preserve">
<value>胡桃服务可用性监控</value>
</data>
<data name="ViewPageFeedbackServerStatusHeader" xml:space="preserve">
<value>胡桃服务</value>
</data>
<data name="ViewPageGachaLogAggressiveRefresh" xml:space="preserve">
<value>全量式重整</value>
</data>
@@ -2076,7 +2016,7 @@
<value>至少需要八個字元</value>
</data>
<data name="ViewPageHutaoPassportRegisterHeader" xml:space="preserve">
<value>建立帳號</value>
<value>註冊</value>
</data>
<data name="ViewPageHutaoPassportResetPasswordHeader" xml:space="preserve">
<value>重設密碼</value>
@@ -2172,10 +2112,10 @@
<value>在指定的屏幕上運行</value>
</data>
<data name="ViewPageLaunchGameMonitorsHeader" xml:space="preserve">
<value>顯示器</value>
<value>螢幕</value>
</data>
<data name="ViewPageLaunchGameMultipleInstancesDescription" xml:space="preserve">
<value>同時運行多個戲用戶端</value>
<value>同時運行多個戲用戶端</value>
</data>
<data name="ViewPageLaunchGameMultipleInstancesHeader" xml:space="preserve">
<value>多用戶端</value>
@@ -2208,7 +2148,7 @@
<value>預下載</value>
</data>
<data name="ViewPageLaunchGameSelectGamePath" xml:space="preserve">
<value>選擇遊戲路徑</value>
<value>选择游戏路径</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountAttachUidNull" xml:space="preserve">
<value>該用戶尚未綁定即時便箋通知 UID</value>
@@ -2223,7 +2163,7 @@
<value>檢測</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountHeader" xml:space="preserve">
<value>檢測號</value>
<value>檢測號</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountRemoveToolTip" xml:space="preserve">
<value>刪除</value>
@@ -2232,7 +2172,7 @@
<value>重新命名</value>
</data>
<data name="ViewPageLaunchGameSwitchSchemeDescription" xml:space="preserve">
<value>切換戲伺服器(服/渠道服/國際服)</value>
<value>切換戲伺服器(服/渠道服/國際服)</value>
</data>
<data name="ViewPageLaunchGameSwitchSchemeHeader" xml:space="preserve">
<value>伺服器</value>
@@ -2252,12 +2192,6 @@
<data name="ViewPageLaunchGameUnlockFpsOn" xml:space="preserve">
<value>啟用</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRDescription" xml:space="preserve">
<value>充分利用支援 HDR 的顯示器以獲得更亮、更生動、更精細的畫面</value>
</data>
<data name="ViewPageLaunchGameWindowsHDRHeader" xml:space="preserve">
<value>Windows HDR</value>
</data>
<data name="ViewPageLoginHoyoverseUserHint" xml:space="preserve">
<value>請輸入您的 HoYoLAB UID</value>
</data>
@@ -2280,7 +2214,7 @@
<value>外觀</value>
</data>
<data name="ViewPageSettingApperanceLanguageDescription" xml:space="preserve">
<value>設定呈現語言</value>
<value>設定系統語言</value>
</data>
<data name="ViewPageSettingApperanceLanguageHeader" xml:space="preserve">
<value>語言</value>
@@ -2292,7 +2226,7 @@
<value>背景材質</value>
</data>
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
<value>圖片存存放在此</value>
<value>圖片存存放在此</value>
</data>
<data name="ViewPageSettingCacheFolderHeader" xml:space="preserve">
<value>暫存檔案夾</value>
@@ -2304,7 +2238,7 @@
<value>創建</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutDescription" xml:space="preserve">
<value>在桌面上創建預設以系統管理員方式啟動的捷徑</value>
<value>在桌面上創建預設以管理員方式啟動的快捷方式</value>
</data>
<data name="ViewPageSettingCreateDesktopShortcutHeader" xml:space="preserve">
<value>創建快捷方式</value>
@@ -2349,13 +2283,13 @@
<value>設備 IP</value>
</data>
<data name="ViewPageSettingElevatedModeDescription" xml:space="preserve">
<value>系統管理模式會影響部分功能的可用性與行為</value>
<value>管理模式会影响部分功能的可用性与行为</value>
</data>
<data name="ViewPageSettingElevatedModeHeader" xml:space="preserve">
<value>系統管理模式</value>
<value>管理模式</value>
</data>
<data name="ViewPageSettingElevatedModeRestartAction" xml:space="preserve">
<value>以系統管理員身分重啟動</value>
<value>以管理员身份重启</value>
</data>
<data name="ViewPageSettingEmptyHistoryVisibleDescription" xml:space="preserve">
<value>在祈願紀錄頁面顯示或隱藏無記錄的歷史祈願活動</value>
@@ -2379,7 +2313,7 @@
<value>祈願記錄</value>
</data>
<data name="ViewPageSettingGameHeader" xml:space="preserve">
<value>戲</value>
<value>戲</value>
</data>
<data name="ViewPageSettingGeetestCustomUrlAction" xml:space="preserve">
<value>配置</value>
@@ -2394,10 +2328,10 @@
<value>無感驗證</value>
</data>
<data name="ViewPageSettingHomeAnnouncementRegionDescription" xml:space="preserve">
<value>選擇想要取公告的遊戲伺服器</value>
<value>选择想要取公告的游戏服务器</value>
</data>
<data name="ViewPageSettingHomeAnnouncementRegionHeader" xml:space="preserve">
<value>公告所屬伺服器</value>
<value>公告所属服务器</value>
</data>
<data name="ViewpageSettingHomeCardDescription" xml:space="preserve">
<value>管理主頁儀表板中的卡片</value>
@@ -2427,7 +2361,7 @@
<value>主頁</value>
</data>
<data name="ViewPageSettingHutaoPassportDangerZoneDescription" xml:space="preserve">
<value>三思而行</value>
<value>三思而行</value>
</data>
<data name="ViewPageSettingHutaoPassportDangerZoneHeader" xml:space="preserve">
<value>危險操作</value>
@@ -2508,10 +2442,10 @@
<value>設置路徑</value>
</data>
<data name="ViewPageSettingSetGamePathHeader" xml:space="preserve">
<value>戲路徑</value>
<value>戲路徑</value>
</data>
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
<value>設置戲路徑時,請選擇戲本體YuanShen.exe 或 GenshinImpact.exe 而不是動器launcher.exe</value>
<value>設置戲路徑時,請選擇戲本體YuanShen.exe 或 GenshinImpact.exe 而不是動器launcher.exe</value>
</data>
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
<value>Shell 體驗</value>
@@ -2622,7 +2556,7 @@
<value>登入失敗,請重新登入</value>
</data>
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
<value>立即登入或建立帳號</value>
<value>立即登入或註冊</value>
</data>
<data name="ViewSettingAllocConsoleDescription" xml:space="preserve">
<value>控制胡桃啟動時是否開啟主控台,重新啟動後生效</value>
@@ -2630,18 +2564,9 @@
<data name="ViewSettingAllocConsoleHeader" xml:space="preserve">
<value>偵錯主控台</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderDescription" xml:space="preserve">
<value>在啟動遊戲中轉換伺服器後會產生對應的遊戲用戶端檔案用作暫存</value>
</data>
<data name="ViewSettingDeleteServerCacheFolderHeader" xml:space="preserve">
<value>刪除轉換伺服器暫存</value>
</data>
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
<value>打開檔案夾</value>
</data>
<data name="ViewSettingHeader" xml:space="preserve">
<value>設定</value>
</data>
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
<value>角色出場率 = 本層上陣該角色次數(層內重複出現只記一次)/ 深淵記錄總數</value>
</data>
@@ -2709,10 +2634,10 @@
<value>上傳資料</value>
</data>
<data name="ViewTitileUpdatePackageReadyContent" xml:space="preserve">
<value>是否立即安</value>
<value>是否立即安</value>
</data>
<data name="ViewTitileUpdatePackageReadyTitle" xml:space="preserve">
<value>胡桃 {0} 版本已準備就緒</value>
<value>胡桃 {0} 版本已准备就绪</value>
</data>
<data name="ViewTitleAutoClicking" xml:space="preserve">
<value>自動連續點按</value>
@@ -2748,10 +2673,10 @@
<value>領取簽到獎勵</value>
</data>
<data name="ViewUserCopyCookieAction" xml:space="preserve">
<value>複製 Cookie</value>
<value>拷貝 Cookie</value>
</data>
<data name="ViewUserDefaultDescription" xml:space="preserve">
<value>請先登</value>
<value>請先登</value>
</data>
<data name="ViewUserDocumentationHeader" xml:space="preserve">
<value>文檔</value>
@@ -2760,10 +2685,10 @@
<value>尚未登入</value>
</data>
<data name="ViewUserRefreshCookieTokenSuccess" xml:space="preserve">
<value>更新 CookieToken 成功</value>
<value>重整 CookieToken 成功</value>
</data>
<data name="ViewUserRefreshCookieTokenWarning" xml:space="preserve">
<value>新 CookieToken 失敗</value>
<value>新 CookieToken 失敗</value>
</data>
<data name="ViewUserRemoveAction" xml:space="preserve">
<value>移除用戶</value>
@@ -2775,7 +2700,7 @@
<value>用戶</value>
</data>
<data name="ViewWelcomeBase" xml:space="preserve">
<value>我們將你下載最基本的圖像資源</value>
<value>我們將你下載最基本的圖像資源</value>
</data>
<data name="ViewWelcomeBody" xml:space="preserve">
<value>你可以繼續使用電腦,絲毫不受影響</value>
@@ -2822,9 +2747,6 @@
<data name="WebAnnouncementTimeHoursEndFormat" xml:space="preserve">
<value>{0} 小時後結束</value>
</data>
<data name="WebBridgeShareCopyToClipboardFailed" xml:space="preserve">
<value>打開剪貼簿失敗</value>
</data>
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>已複製到剪貼簿</value>
</data>
@@ -2832,10 +2754,10 @@
<value>全部完成</value>
</data>
<data name="WebDailyNoteArchonQuestStatusNotOpen" xml:space="preserve">
<value>尚未開啟</value>
<value>尚未开启</value>
</data>
<data name="WebDailyNoteArchonQuestStatusOngoing" xml:space="preserve">
<value>行中</value>
<value>行中</value>
</data>
<data name="WebDailyNoteAttendanceRewardStatusFinishedNonReward" xml:space="preserve">
<value>已完成</value>
@@ -2925,7 +2847,7 @@
<value>{0} 秒</value>
</data>
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米社-旅行工具-原神战绩-实时便笺」页面查看</value>
<value>驗證失敗,請手動驗證或前往「米社-我的角色-實時便箋」頁面查看</value>
</data>
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
<value>錯誤的 UID 格式</value>
@@ -2967,45 +2889,42 @@
<value>下載連結複製成功</value>
</data>
<data name="WebHoyolabInvalidRegion" xml:space="preserve">
<value>效的服器</value>
<value>效的服器</value>
</data>
<data name="WebHoyolabInvalidUid" xml:space="preserve">
<value>無效的 UID</value>
</data>
<data name="WebHoyolabRegionCNGF01" xml:space="preserve">
<value>服 官方服</value>
<value>服 官方服</value>
</data>
<data name="WebHoyolabRegionCNQD01" xml:space="preserve">
<value>服 渠道服</value>
<value>服 渠道服</value>
</data>
<data name="WebHoyolabRegionOSASIA" xml:space="preserve">
<value>國際服</value>
<value>国际服</value>
</data>
<data name="WebHoyolabRegionOSCHT" xml:space="preserve">
<value>國際服 港澳台服</value>
<value>国际服 港澳台服</value>
</data>
<data name="WebHoyolabRegionOSEURO" xml:space="preserve">
<value>國際服</value>
<value>国际服</value>
</data>
<data name="WebHoyolabRegionOSUSA" xml:space="preserve">
<value>國際服 美服</value>
<value>国际服 美服</value>
</data>
<data name="WebHutaoServiceUnAvailable" xml:space="preserve">
<value>胡桃服務維護中</value>
</data>
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
<value>验证失败,请手动验证或前往「米社-旅行工具-原神战绩」页面查看</value>
<value>驗證失敗,請手動驗證或前往「米社-我的角色」頁面查看</value>
</data>
<data name="WebResponseFormat" xml:space="preserve">
<value>狀態:{0} | 信息:{1}</value>
</data>
<data name="WebResponseRefreshCookieHintFormat" xml:space="preserve">
<value>請新 Cookie原始消息{0}</value>
<value>請新 Cookie原始消息{0}</value>
</data>
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
<value>[{0}] 中的 [{1}] 網路請求異常,請稍後再試</value>
</data>
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
<value>顯示器編號</value>
</data>
</root>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -6,6 +6,7 @@ using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Web.Hoyolab;
using System.Globalization;
namespace Snap.Hutao.Service;
@@ -15,6 +16,7 @@ internal sealed partial class AppOptions : DbStoreOptions
{
private bool? isEmptyHistoryWishVisible;
private BackdropType? backdropType;
private CultureInfo? currentCulture;
private Region? region;
private string? geetestCustomCompositeUrl;
@@ -24,7 +26,7 @@ internal sealed partial class AppOptions : DbStoreOptions
set => SetOption(ref isEmptyHistoryWishVisible, SettingEntry.IsEmptyHistoryWishVisible, value);
}
public List<NameValue<BackdropType>> BackdropTypes { get; } = CollectionsNameValue.FromEnum<BackdropType>(type => type >= 0);
public List<NameValue<BackdropType>> BackdropTypes { get; } = CollectionsNameValue.FromEnum<BackdropType>();
public BackdropType BackdropType
{
@@ -32,6 +34,14 @@ internal sealed partial class AppOptions : DbStoreOptions
set => SetOption(ref backdropType, SettingEntry.SystemBackdropType, value, value => value.ToStringOrEmpty());
}
public List<NameValue<CultureInfo>> Cultures { get; } = SupportedCultures.Get();
public CultureInfo CurrentCulture
{
get => GetOption(ref currentCulture, SettingEntry.Culture, CultureInfo.GetCultureInfo, CultureInfo.CurrentCulture);
set => SetOption(ref currentCulture, SettingEntry.Culture, value, value => value.Name);
}
public Lazy<List<NameValue<Region>>> LazyRegions { get; } = new(KnownRegions.Get);
public Region Region
@@ -45,4 +55,6 @@ internal sealed partial class AppOptions : DbStoreOptions
get => GetOption(ref geetestCustomCompositeUrl, SettingEntry.GeetestCustomCompositeUrl);
set => SetOption(ref geetestCustomCompositeUrl, SettingEntry.GeetestCustomCompositeUrl, value);
}
internal CultureInfo PreviousCulture { get; set; } = default!;
}

View File

@@ -3,11 +3,17 @@
using Snap.Hutao.Model;
using Snap.Hutao.Web.Hoyolab;
using System.Globalization;
namespace Snap.Hutao.Service;
internal static class AppOptionsExtension
{
public static NameValue<CultureInfo>? GetCurrentCultureForSelectionOrDefault(this AppOptions appOptions)
{
return appOptions.Cultures.SingleOrDefault(c => c.Value == appOptions.CurrentCulture);
}
public static NameValue<Region>? GetCurrentRegionForSelectionOrDefault(this AppOptions appOptions)
{
return appOptions.LazyRegions.Value.SingleOrDefault(c => c.Value.Value == appOptions.Region.Value);

View File

@@ -1,43 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Abstraction;
using System.Globalization;
namespace Snap.Hutao.Service;
[ConstructorGenerated(CallBaseConstructor = true)]
[Injection(InjectAs.Singleton)]
internal sealed partial class CultureOptions : DbStoreOptions
{
private CultureInfo? currentCulture;
private string? localeName;
private string? languageCode;
public List<NameValue<CultureInfo>> Cultures { get; } = SupportedCultures.Get();
public CultureInfo CurrentCulture
{
get => GetOption(ref currentCulture, SettingEntry.Culture, CultureInfo.GetCultureInfo, CultureInfo.CurrentCulture);
set => SetOption(ref currentCulture, SettingEntry.Culture, value, value => value.Name);
}
public CultureInfo SystemCulture { get; set; } = default!;
public string LocaleName { get => localeName ??= CultureOptionsExtension.GetLocaleName(CurrentCulture); }
public string LanguageCode
{
get
{
if (languageCode is null && !LocaleNames.TryGetLanguageCodeFromLocaleName(LocaleName, out languageCode))
{
throw new KeyNotFoundException($"Invalid localeName: '{LocaleName}'");
}
return languageCode;
}
}
}

View File

@@ -172,8 +172,6 @@ internal static class DiscordController
private static async ValueTask DiscordRunCallbacksAsync(CancellationToken cancellationToken)
{
int notRunningCounter = 0;
using (PeriodicTimer timer = new(TimeSpan.FromMilliseconds(500)))
{
try
@@ -192,18 +190,7 @@ internal static class DiscordController
DiscordResult result = DiscordCoreRunRunCallbacks();
if (result is not DiscordResult.Ok)
{
if (result is DiscordResult.NotRunning)
{
if (++notRunningCounter > 20)
{
Stop();
}
}
else
{
notRunningCounter = 0;
System.Diagnostics.Debug.WriteLine($"[Discord.GameSDK ERROR]:{result:D} {result}");
}
System.Diagnostics.Debug.WriteLine($"[Discord.GameSDK ERROR]:{result:D} {result}");
}
}
catch (SEHException ex)

View File

@@ -226,7 +226,7 @@ internal sealed partial class GachaLogService : IGachaLogService
break;
}
await Delay.RandomMilliSeconds(1000, 2000).ConfigureAwait(false);
await Delay.Random(1000, 2000).ConfigureAwait(false);
}
while (true);
@@ -238,7 +238,7 @@ internal sealed partial class GachaLogService : IGachaLogService
// save items for each queryType
token.ThrowIfCancellationRequested();
fetchContext.SaveItems();
await Delay.RandomMilliSeconds(1000, 2000).ConfigureAwait(false);
await Delay.Random(1000, 2000).ConfigureAwait(false);
}
return new(!fetchContext.FetchStatus.AuthKeyTimeout, fetchContext.TargetArchive);

View File

@@ -18,7 +18,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryProvider
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
/// <inheritdoc/>
public async ValueTask<ValueResult<bool, GachaLogQuery>> GetQueryAsync()
@@ -33,13 +33,13 @@ internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryP
if (query.TryGetSingleValue("auth_appid", out string? appId) && appId is "webview_gacha")
{
string? queryLanguageCode = query["lang"];
if (cultureOptions.LanguageCodeFitsCurrentLocale(queryLanguageCode))
if (metadataOptions.LanguageCodeFitsCurrentLocale(queryLanguageCode))
{
return new(true, new(queryString));
}
else
{
string message = SH.FormatServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale(queryLanguageCode, cultureOptions.LanguageCode);
string message = SH.FormatServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale(queryLanguageCode, metadataOptions.LanguageCode);
return new(false, message);
}
}

View File

@@ -20,7 +20,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvider
{
private readonly BindingClient2 bindingClient2;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
private readonly IUserService userService;
/// <inheritdoc/>
@@ -38,7 +38,7 @@ internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvid
if (authkeyResponse.IsOk())
{
return new(true, new(ComposeQueryString(data, authkeyResponse.Data, cultureOptions.LanguageCode)));
return new(true, new(ComposeQueryString(data, authkeyResponse.Data, metadataOptions.LanguageCode)));
}
else
{

View File

@@ -22,7 +22,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProvider
{
private readonly IGameServiceFacade gameService;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
/// <summary>
/// 获取缓存文件路径
@@ -90,12 +90,12 @@ internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProv
NameValueCollection query = HttpUtility.ParseQueryString(result.TrimEnd("#/log"));
string? queryLanguageCode = query["lang"];
if (cultureOptions.LanguageCodeFitsCurrentLocale(queryLanguageCode))
if (metadataOptions.LanguageCodeFitsCurrentLocale(queryLanguageCode))
{
return new(true, new(result));
}
string message = SH.FormatServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale(queryLanguageCode, cultureOptions.LanguageCode);
string message = SH.FormatServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale(queryLanguageCode, metadataOptions.LanguageCode);
return new(false, message);
}
}

View File

@@ -17,7 +17,7 @@ internal sealed partial class UIGFExportService : IUIGFExportService
{
private readonly IGachaLogDbService gachaLogDbService;
private readonly RuntimeOptions runtimeOptions;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
private readonly ITaskContext taskContext;
/// <inheritdoc/>
@@ -31,7 +31,7 @@ internal sealed partial class UIGFExportService : IUIGFExportService
UIGF uigf = new()
{
Info = UIGFInfo.From(runtimeOptions, cultureOptions, archive.Uid),
Info = UIGFInfo.From(runtimeOptions, metadataOptions, archive.Uid),
List = list,
};

View File

@@ -18,7 +18,7 @@ namespace Snap.Hutao.Service.GachaLog;
internal sealed partial class UIGFImportService : IUIGFImportService
{
private readonly ILogger<UIGFImportService> logger;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
private readonly IGachaLogDbService gachaLogDbService;
private readonly ITaskContext taskContext;
@@ -37,9 +37,9 @@ internal sealed partial class UIGFImportService : IUIGFImportService
// v2.1 only support CHS
if (version is UIGFVersion.Major2Minor2OrLower)
{
if (!cultureOptions.LanguageCodeFitsCurrentLocale(uigf.Info.Language))
if (!metadataOptions.LanguageCodeFitsCurrentLocale(uigf.Info.Language))
{
string message = SH.FormatServiceGachaUIGFImportLanguageNotMatch(uigf.Info.Language, cultureOptions.LanguageCode);
string message = SH.FormatServiceGachaUIGFImportLanguageNotMatch(uigf.Info.Language, metadataOptions.LanguageCode);
ThrowHelper.InvalidOperation(message);
}

View File

@@ -29,9 +29,10 @@ internal readonly struct ChannelOptions
/// </summary>
public readonly bool IsOversea;
public readonly ChannelOptionsErrorKind ErrorKind;
public readonly string? FilePath;
/// <summary>
/// 配置文件路径 当不为 null 时则存在文件读写问题
/// </summary>
public readonly string? ConfigFilePath;
public ChannelOptions(ChannelType channel, SubChannelType subChannel, bool isOversea)
{
@@ -47,20 +48,15 @@ internal readonly struct ChannelOptions
IsOversea = isOversea;
}
private ChannelOptions(ChannelOptionsErrorKind errorKind, string? filePath)
private ChannelOptions(bool isOversea, string? configFilePath)
{
ErrorKind = errorKind;
FilePath = filePath;
IsOversea = isOversea;
ConfigFilePath = configFilePath;
}
public static ChannelOptions ConfigurationFileNotFound(string filePath)
public static ChannelOptions FileNotFound(bool isOversea, string configFilePath)
{
return new(ChannelOptionsErrorKind.ConfigurationFileNotFound, filePath);
}
public static ChannelOptions GamePathNullOrEmpty()
{
return new(ChannelOptionsErrorKind.GamePathNullOrEmpty, string.Empty);
return new(isOversea, configFilePath);
}
/// <inheritdoc/>

View File

@@ -1,11 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Game.Configuration;
internal enum ChannelOptionsErrorKind
{
None,
ConfigurationFileNotFound,
GamePathNullOrEmpty,
}

View File

@@ -1,9 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO.Ini;
using Snap.Hutao.Service.Game.Scheme;
using System.IO;
using static Snap.Hutao.Service.Game.GameConstants;
namespace Snap.Hutao.Service.Game.Configuration;
@@ -15,22 +17,25 @@ internal sealed partial class GameChannelOptionsService : IGameChannelOptionsSer
public ChannelOptions GetChannelOptions()
{
if (!launchOptions.TryGetGameFileSystem(out GameFileSystem? gameFileSystem))
if (!launchOptions.TryGetGamePathAndFilePathByName(ConfigFileName, out string gamePath, out string? configPath))
{
return ChannelOptions.GamePathNullOrEmpty();
throw ThrowHelper.InvalidOperation($"Invalid game path: {gamePath}");
}
bool isOversea = LaunchScheme.ExecutableIsOversea(gameFileSystem.GameFileName);
bool isOversea = LaunchScheme.ExecutableIsOversea(Path.GetFileName(gamePath));
if (!File.Exists(gameFileSystem.GameConfigFilePath))
if (!File.Exists(configPath))
{
return ChannelOptions.ConfigurationFileNotFound(gameFileSystem.GameConfigFilePath);
return ChannelOptions.FileNotFound(isOversea, configPath);
}
List<IniParameter> parameters = IniSerializer.DeserializeFromFile(gameFileSystem.GameConfigFilePath).OfType<IniParameter>().ToList();
string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value;
string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value;
using (FileStream stream = File.OpenRead(configPath))
{
List<IniParameter> parameters = IniSerializer.Deserialize(stream).OfType<IniParameter>().ToList();
string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value;
string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value;
return new(channel, subChannel, isOversea);
return new(channel, subChannel, isOversea);
}
}
}

View File

@@ -10,7 +10,6 @@ namespace Snap.Hutao.Service.Game;
internal static class GameConstants
{
public const string ConfigFileName = "config.ini";
public const string PCGameSDKFilePath = @"YuanShen_Data\Plugins\PCGameSDK.dll";
public const string YuanShenFileName = "YuanShen.exe";
public const string YuanShenFileNameUpper = "YUANSHEN.EXE";
public const string GenshinImpactFileName = "GenshinImpact.exe";

View File

@@ -1,39 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.IO;
namespace Snap.Hutao.Service.Game;
internal sealed class GameFileSystem
{
private readonly string gameFilePath;
private string? gameFileName;
private string? gameDirectory;
private string? gameConfigFilePath;
private string? pcGameSDKFilePath;
public GameFileSystem(string gameFilePath)
{
this.gameFilePath = gameFilePath;
}
public string GameFilePath { get => gameFilePath; }
public string GameFileName { get => gameFileName ??= Path.GetFileName(gameFilePath); }
public string GameDirectory
{
get
{
gameDirectory ??= Path.GetDirectoryName(gameFilePath);
ArgumentException.ThrowIfNullOrEmpty(gameDirectory);
return gameDirectory;
}
}
public string GameConfigFilePath { get => gameConfigFilePath ??= Path.Combine(GameDirectory, GameConstants.ConfigFileName); }
public string PCGameSDKFilePath { get => pcGameSDKFilePath ??= Path.Combine(GameDirectory, GameConstants.PCGameSDKFilePath); }
}

View File

@@ -218,7 +218,8 @@ internal sealed class LaunchOptions : DbStoreOptions
{
if (SetProperty(ref selectedAspectRatio, value) && value is AspectRatio aspectRatio)
{
(ScreenWidth, ScreenHeight) = ((int)aspectRatio.Width, (int)aspectRatio.Height);
ScreenWidth = (int)aspectRatio.Width;
ScreenHeight = (int)aspectRatio.Height;
}
}
}

View File

@@ -3,25 +3,70 @@
using Snap.Hutao.Service.Game.PathAbstraction;
using System.Collections.Immutable;
using System.IO;
namespace Snap.Hutao.Service.Game;
internal static class LaunchOptionsExtension
{
public static bool TryGetGameFileSystem(this LaunchOptions options, [NotNullWhen(true)] out GameFileSystem? fileSystem)
public static bool TryGetGamePathAndGameDirectory(this LaunchOptions options, out string gamePath, [NotNullWhen(true)] out string? gameDirectory)
{
string gamePath = options.GamePath;
gamePath = options.GamePath;
if (string.IsNullOrEmpty(gamePath))
gameDirectory = Path.GetDirectoryName(gamePath);
if (string.IsNullOrEmpty(gameDirectory))
{
fileSystem = default;
return false;
}
fileSystem = new GameFileSystem(gamePath);
return true;
}
public static bool TryGetGameDirectoryAndGameFileName(this LaunchOptions options, [NotNullWhen(true)] out string? gameDirectory, [NotNullWhen(true)] out string? gameFileName)
{
string gamePath = options.GamePath;
gameDirectory = Path.GetDirectoryName(gamePath);
if (string.IsNullOrEmpty(gameDirectory))
{
gameFileName = default;
return false;
}
gameFileName = Path.GetFileName(gamePath);
if (string.IsNullOrEmpty(gameFileName))
{
return false;
}
return true;
}
public static bool TryGetGamePathAndGameFileName(this LaunchOptions options, out string gamePath, [NotNullWhen(true)] out string? gameFileName)
{
gamePath = options.GamePath;
gameFileName = Path.GetFileName(gamePath);
if (string.IsNullOrEmpty(gameFileName))
{
return false;
}
return true;
}
public static bool TryGetGamePathAndFilePathByName(this LaunchOptions options, string fileName, out string gamePath, [NotNullWhen(true)] out string? filePath)
{
if (options.TryGetGamePathAndGameDirectory(out gamePath, out string? gameDirectory))
{
filePath = Path.Combine(gameDirectory, fileName);
return true;
}
filePath = default;
return false;
}
public static ImmutableList<GamePathEntry> GetGamePathEntries(this LaunchOptions options, out GamePathEntry? entry)
{
string gamePath = options.GamePath;

View File

@@ -5,11 +5,12 @@ using Microsoft.Win32.SafeHandles;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Factory.Progress;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Service.Game.Package;
using Snap.Hutao.Service.Game.PathAbstraction;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
using Snap.Hutao.Web.Response;
using System.Collections.Immutable;
using System.IO;
namespace Snap.Hutao.Service.Game.Launching.Handler;
@@ -18,67 +19,38 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
{
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
{
if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem))
IServiceProvider serviceProvider = context.ServiceProvider;
IContentDialogFactory contentDialogFactory = serviceProvider.GetRequiredService<IContentDialogFactory>();
IProgressFactory progressFactory = serviceProvider.GetRequiredService<IProgressFactory>();
LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync<LaunchGamePackageConvertDialog>().ConfigureAwait(false);
IProgress<PackageConvertStatus> convertProgress = progressFactory.CreateForMainThread<PackageConvertStatus>(state => dialog.State = state);
using (await dialog.BlockAsync(context.TaskContext).ConfigureAwait(false))
{
return;
}
if (ShouldConvert(context, gameFileSystem))
{
IServiceProvider serviceProvider = context.ServiceProvider;
IContentDialogFactory contentDialogFactory = serviceProvider.GetRequiredService<IContentDialogFactory>();
IProgressFactory progressFactory = serviceProvider.GetRequiredService<IProgressFactory>();
LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync<LaunchGamePackageConvertDialog>().ConfigureAwait(false);
IProgress<PackageConvertStatus> convertProgress = progressFactory.CreateForMainThread<PackageConvertStatus>(state => dialog.State = state);
using (await dialog.BlockAsync(context.TaskContext).ConfigureAwait(false))
if (!await EnsureGameResourceAsync(context, convertProgress).ConfigureAwait(false))
{
if (!await EnsureGameResourceAsync(context, gameFileSystem, convertProgress).ConfigureAwait(false))
{
// context.Result is set in EnsureGameResourceAsync
return;
}
await context.TaskContext.SwitchToMainThreadAsync();
context.UpdateGamePathEntry();
// context.Result is set in EnsureGameResourceAsync
return;
}
await context.TaskContext.SwitchToMainThreadAsync();
ImmutableList<GamePathEntry> gamePathEntries = context.Options.GetGamePathEntries(out GamePathEntry? selected);
context.ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selected);
}
await next().ConfigureAwait(false);
}
private static bool ShouldConvert(LaunchExecutionContext context, GameFileSystem gameFileSystem)
private static async ValueTask<bool> EnsureGameResourceAsync(LaunchExecutionContext context, IProgress<PackageConvertStatus> progress)
{
// Configuration file changed
if (context.ChannelOptionsChanged)
if (!context.Options.TryGetGameDirectoryAndGameFileName(out string? gameFolder, out string? gameFileName))
{
return true;
context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath;
context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid;
return false;
}
// Executable name not match
if (!context.Scheme.ExecutableMatches(gameFileSystem.GameFileName))
{
return true;
}
if (!context.Scheme.IsOversea)
{
// [It's Bilibili channel xor PCGameSDK.dll exists] means we need to convert
if (context.Scheme.Channel is ChannelType.Bili ^ File.Exists(gameFileSystem.PCGameSDKFilePath))
{
return true;
}
}
return false;
}
private static async ValueTask<bool> EnsureGameResourceAsync(LaunchExecutionContext context, GameFileSystem gameFileSystem, IProgress<PackageConvertStatus> progress)
{
string gameFolder = gameFileSystem.GameDirectory;
string gameFileName = gameFileSystem.GameFileName;
context.Logger.LogInformation("Game folder: {GameFolder}", gameFolder);
if (!CheckDirectoryPermissions(gameFolder))

View File

@@ -3,7 +3,7 @@
namespace Snap.Hutao.Service.Game.Launching.Handler;
internal sealed class LaunchExecutionEnsureSchemeHandler : ILaunchExecutionDelegateHandler
internal sealed class LaunchExecutionEnsureSchemeNotExistsHandler : ILaunchExecutionDelegateHandler
{
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
{
@@ -14,7 +14,7 @@ internal sealed class LaunchExecutionEnsureSchemeHandler : ILaunchExecutionDeleg
return;
}
context.Logger.LogInformation("Scheme [{Scheme}] is selected", context.Scheme.DisplayName);
context.Logger.LogInformation("Scheme[{Scheme}] is selected", context.Scheme.DisplayName);
await next().ConfigureAwait(false);
}
}

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Core;
using System.IO;
namespace Snap.Hutao.Service.Game.Launching.Handler;
@@ -9,19 +10,21 @@ internal sealed class LaunchExecutionGameProcessInitializationHandler : ILaunchE
{
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
{
if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem))
if (!context.Options.TryGetGamePathAndGameFileName(out string gamePath, out string? gameFileName))
{
context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath;
context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid;
return;
}
context.Progress.Report(new(LaunchPhase.ProcessInitializing, SH.ServiceGameLaunchPhaseProcessInitializing));
using (context.Process = InitializeGameProcess(context, gameFileSystem))
using (context.Process = InitializeGameProcess(context, gamePath))
{
await next().ConfigureAwait(false);
}
}
private static System.Diagnostics.Process InitializeGameProcess(LaunchExecutionContext context, GameFileSystem gameFileSystem)
private static System.Diagnostics.Process InitializeGameProcess(LaunchExecutionContext context, string gamePath)
{
LaunchOptions launchOptions = context.Options;
@@ -48,10 +51,10 @@ internal sealed class LaunchExecutionGameProcessInitializationHandler : ILaunchE
StartInfo = new()
{
Arguments = commandLine,
FileName = gameFileSystem.GameFilePath,
FileName = gamePath,
UseShellExecute = true,
Verb = "runas",
WorkingDirectory = gameFileSystem.GameDirectory,
WorkingDirectory = Path.GetDirectoryName(gamePath),
},
};
}

View File

@@ -11,19 +11,22 @@ internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecution
{
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
{
if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem))
if (!context.Options.TryGetGamePathAndFilePathByName(GameConstants.ConfigFileName, out string gamePath, out string? configPath))
{
// context.Result is set in TryGetGameFileSystem
context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath;
context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid;
return;
}
string configPath = gameFileSystem.GameConfigFilePath;
context.Logger.LogInformation("Game config file path: {ConfigPath}", configPath);
List<IniElement> elements = default!;
try
{
elements = [.. IniSerializer.DeserializeFromFile(configPath)];
using (FileStream readStream = File.OpenRead(configPath))
{
elements = [.. IniSerializer.Deserialize(readStream)];
}
}
catch (FileNotFoundException)
{
@@ -44,27 +47,32 @@ internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecution
return;
}
bool changed = false;
foreach (IniElement element in elements)
{
if (element is IniParameter parameter)
{
if (parameter.Key is ChannelOptions.ChannelName)
{
context.ChannelOptionsChanged = parameter.Set(context.Scheme.Channel.ToString("D")) || context.ChannelOptionsChanged;
changed = parameter.Set(context.Scheme.Channel.ToString("D")) || changed;
continue;
}
if (parameter.Key is ChannelOptions.SubChannelName)
{
context.ChannelOptionsChanged = parameter.Set(context.Scheme.SubChannel.ToString("D")) || context.ChannelOptionsChanged;
changed = parameter.Set(context.Scheme.SubChannel.ToString("D")) || changed;
continue;
}
}
}
if (context.ChannelOptionsChanged)
if (changed)
{
IniSerializer.SerializeToFile(configPath, elements);
using (FileStream writeStream = File.Create(configPath))
{
IniSerializer.Serialize(writeStream, elements);
}
}
await next().ConfigureAwait(false);

View File

@@ -2,10 +2,8 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game.PathAbstraction;
using Snap.Hutao.Service.Game.Scheme;
using Snap.Hutao.ViewModel.Game;
using System.Collections.Immutable;
namespace Snap.Hutao.Service.Game.Launching;
@@ -17,8 +15,6 @@ internal sealed partial class LaunchExecutionContext
private readonly ITaskContext taskContext;
private readonly LaunchOptions options;
private GameFileSystem? gameFileSystem;
[SuppressMessage("", "SH007")]
public LaunchExecutionContext(IServiceProvider serviceProvider, IViewModelSupportLaunchExecution viewModel, LaunchScheme? scheme, GameAccount? account)
: this(serviceProvider)
@@ -40,43 +36,13 @@ internal sealed partial class LaunchExecutionContext
public LaunchOptions Options { get => options; }
public IViewModelSupportLaunchExecution ViewModel { get; private set; } = default!;
public IViewModelSupportLaunchExecution ViewModel { get; set; } = default!;
public LaunchScheme Scheme { get; private set; } = default!;
public LaunchScheme Scheme { get; set; } = default!;
public GameAccount? Account { get; private set; }
public bool ChannelOptionsChanged { get; set; }
public GameAccount? Account { get; set; }
public IProgress<LaunchStatus> Progress { get; set; } = default!;
public System.Diagnostics.Process Process { get; set; } = default!;
public bool TryGetGameFileSystem([NotNullWhen(true)] out GameFileSystem? gameFileSystem)
{
if (this.gameFileSystem is not null)
{
gameFileSystem = this.gameFileSystem;
return true;
}
if (!Options.TryGetGameFileSystem(out gameFileSystem))
{
Result.Kind = LaunchExecutionResultKind.NoActiveGamePath;
Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid;
return false;
}
this.gameFileSystem = gameFileSystem;
return true;
}
public void UpdateGamePathEntry()
{
ImmutableList<GamePathEntry> gamePathEntries = Options.GetGamePathEntries(out GamePathEntry? selectedEntry);
ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selectedEntry);
// invalidate game file system
gameFileSystem = null;
}
}

View File

@@ -15,7 +15,7 @@ internal sealed class LaunchExecutionInvoker
{
handlers = [];
handlers.Enqueue(new LaunchExecutionEnsureGameNotRunningHandler());
handlers.Enqueue(new LaunchExecutionEnsureSchemeHandler());
handlers.Enqueue(new LaunchExecutionEnsureSchemeNotExistsHandler());
handlers.Enqueue(new LaunchExecutionSetChannelOptionsHandler());
handlers.Enqueue(new LaunchExecutionEnsureGameResourceHandler());
handlers.Enqueue(new LaunchExecutionSetGameAccountHandler());

View File

@@ -93,6 +93,7 @@ internal sealed partial class PackageConverter
ZipFile.ExtractToDirectory(sdkWebStream, gameFolder, true);
}
// TODO: verify sdk md5
if (File.Exists(sdkDllBackup) && File.Exists(sdkVersionBackup))
{
File.Delete(sdkDllBackup);

View File

@@ -9,7 +9,7 @@ internal sealed class GamePathEntry
public string Path { get; set; } = default!;
[JsonIgnore]
public GamePathEntryKind Kind { get => GetKind(Path); }
public GamePathKind Kind { get => GetKind(Path); }
public static GamePathEntry Create(string path)
{
@@ -19,8 +19,8 @@ internal sealed class GamePathEntry
};
}
private static GamePathEntryKind GetKind(string path)
private static GamePathKind GetKind(string path)
{
return GamePathEntryKind.None;
return GamePathKind.None;
}
}

View File

@@ -3,7 +3,7 @@
namespace Snap.Hutao.Service.Game.PathAbstraction;
internal enum GamePathEntryKind
internal enum GamePathKind
{
None,
ChineseClient,

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service;
namespace Snap.Hutao.Service.Metadata;
/// <summary>
/// 本地化名称
@@ -74,15 +74,4 @@ internal static class LocaleNames
return !string.IsNullOrEmpty(languageCode);
}
public static string GetLanguageCodeForDocumentationSearchFromLocaleName(string localeName)
{
return localeName switch
{
ID => "id-id",
RU => "ru-ru",
CHS => "zh-cn",
_ => "en-us",
};
}
}

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core;
using System.Globalization;
using System.IO;
namespace Snap.Hutao.Service.Metadata;
@@ -11,9 +10,10 @@ namespace Snap.Hutao.Service.Metadata;
[Injection(InjectAs.Singleton)]
internal sealed partial class MetadataOptions
{
private readonly CultureOptions cultureOptions;
private readonly RuntimeOptions runtimeOptions;
private readonly AppOptions appOptions;
private readonly RuntimeOptions hutaoOptions;
private string? localeName;
private string? fallbackDataFolder;
private string? localizedDataFolder;
@@ -23,7 +23,7 @@ internal sealed partial class MetadataOptions
{
if (fallbackDataFolder is null)
{
fallbackDataFolder = Path.Combine(runtimeOptions.DataFolder, "Metadata", LocaleNames.CHS);
fallbackDataFolder = Path.Combine(hutaoOptions.DataFolder, "Metadata", "CHS");
Directory.CreateDirectory(fallbackDataFolder);
}
@@ -37,7 +37,7 @@ internal sealed partial class MetadataOptions
{
if (localizedDataFolder is null)
{
localizedDataFolder = Path.Combine(runtimeOptions.DataFolder, "Metadata", cultureOptions.LocaleName);
localizedDataFolder = Path.Combine(hutaoOptions.DataFolder, "Metadata", LocaleName);
Directory.CreateDirectory(localizedDataFolder);
}
@@ -45,13 +45,21 @@ internal sealed partial class MetadataOptions
}
}
public string GetLocalizedLocalFile(string fileNameWithExtension)
public string LocaleName
{
return Path.Combine(LocalizedDataFolder, fileNameWithExtension);
get => localeName ??= MetadataOptionsExtension.GetLocaleName(appOptions.CurrentCulture);
}
public string GetLocalizedRemoteFile(string fileNameWithExtension)
public string LanguageCode
{
return Web.HutaoEndpoints.Metadata(cultureOptions.LocaleName, fileNameWithExtension);
get
{
if (LocaleNames.TryGetLanguageCodeFromLocaleName(LocaleName, out string? languageCode))
{
return languageCode;
}
throw new KeyNotFoundException($"Invalid localeName: '{LocaleName}'");
}
}
}

View File

@@ -1,19 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model;
using System.Globalization;
using System.IO;
namespace Snap.Hutao.Service;
namespace Snap.Hutao.Service.Metadata;
internal static class CultureOptionsExtension
internal static class MetadataOptionsExtension
{
public static NameValue<CultureInfo>? GetCurrentCultureForSelectionOrDefault(this CultureOptions options)
public static string GetLocalizedLocalFile(this MetadataOptions options, string fileNameWithExtension)
{
return options.Cultures.SingleOrDefault(c => c.Value == options.CurrentCulture);
return Path.Combine(options.LocalizedDataFolder, fileNameWithExtension);
}
public static bool LanguageCodeFitsCurrentLocale(this CultureOptions options, string? languageCode)
public static string GetLocalizedRemoteFile(this MetadataOptions options, string fileNameWithExtension)
{
return Web.HutaoEndpoints.Metadata(options.LocaleName, fileNameWithExtension);
}
public static bool LanguageCodeFitsCurrentLocale(this MetadataOptions options, string? languageCode)
{
if (string.IsNullOrEmpty(languageCode))
{
@@ -25,11 +30,6 @@ internal static class CultureOptionsExtension
return GetLocaleName(cultureInfo) == options.LocaleName;
}
public static string GetLanguageCodeForDocumentationSearch(this CultureOptions options)
{
return LocaleNames.GetLanguageCodeForDocumentationSearchFromLocaleName(options.LocaleName);
}
internal static string GetLocaleName(CultureInfo cultureInfo)
{
while (true)

View File

@@ -0,0 +1,44 @@
// 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(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/hutao-API.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

@@ -107,7 +107,6 @@
<None Remove="Control\Theme\Uri.xaml" />
<None Remove="Control\Theme\WindowOverride.xaml" />
<None Remove="GuideWindow.xaml" />
<None Remove="IdentifyMonitorWindow.xaml" />
<None Remove="IdentityStructs.json" />
<None Remove="LaunchGameWindow.xaml" />
<None Remove="Resource\BlurBackground.png" />
@@ -128,7 +127,6 @@
<None Remove="Resource\Navigation\DailyNote.png" />
<None Remove="Resource\Navigation\Database.png" />
<None Remove="Resource\Navigation\Documentation.png" />
<None Remove="Resource\Navigation\Feedback.png" />
<None Remove="Resource\Navigation\GachaLog.png" />
<None Remove="Resource\Navigation\LaunchGame.png" />
<None Remove="Resource\Navigation\SpiralAbyss.png" />
@@ -187,7 +185,6 @@
<None Remove="View\Page\AvatarPropertyPage.xaml" />
<None Remove="View\Page\CultivationPage.xaml" />
<None Remove="View\Page\DailyNotePage.xaml" />
<None Remove="View\Page\FeedbackPage.xaml" />
<None Remove="View\Page\GachaLogPage.xaml" />
<None Remove="View\Page\LaunchGamePage.xaml" />
<None Remove="View\Page\LoginMihoyoUserPage.xaml" />
@@ -271,7 +268,6 @@
<Content Include="Resource\Navigation\DailyNote.png" />
<Content Include="Resource\Navigation\Database.png" />
<Content Include="Resource\Navigation\Documentation.png" />
<Content Include="Resource\Navigation\Feedback.png" />
<Content Include="Resource\Navigation\GachaLog.png" />
<Content Include="Resource\Navigation\LaunchGame.png" />
<Content Include="Resource\Navigation\SpiralAbyss.png" />
@@ -325,7 +321,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556">
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.507">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -348,11 +344,6 @@
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\FeedbackPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Dialog\ReconfirmDialog.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -553,13 +544,7 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="IdentifyMonitorWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Control\HutaoStatisticsCard.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shct="using:Snap.Hutao.Control.Text"
Title="{shcm:ResourceString Name=ViewDialogReconfirmTitle}"
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
DefaultButton="Close"
@@ -17,12 +16,6 @@
<TextBox
Margin="0,0,0,8"
VerticalAlignment="Top"
Style="{StaticResource DefaultTextBoxStyle}"
Text="{x:Bind Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.HeaderTemplate>
<DataTemplate>
<shct:HtmlDescriptionTextBlock Description="{shcm:ResourceString Name=ViewDialogReconfirmTextHeader}"/>
</DataTemplate>
</TextBox.HeaderTemplate>
</TextBox>
Header="{shcm:ResourceString Name=ViewDialogReconfirmTextHeader}"
Text="{x:Bind Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</ContentDialog>

View File

@@ -55,7 +55,7 @@
<GridView
Grid.Row="0"
ItemTemplate="{StaticResource LanguageTemplate}"
ItemsSource="{Binding CultureOptions.Cultures}"
ItemsSource="{Binding AppOptions.Cultures}"
SelectedItem="{Binding SelectedCulture, Mode=TwoWay}"
SelectionMode="Single"/>
</Grid>

View File

@@ -27,10 +27,6 @@
shvh:NavHelper.NavigateTo="shvp:AnnouncementPage"
Content="{shcm:ResourceString Name=ViewAnnouncementHeader}"
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Announcement.png}"/>
<NavigationViewItem
shvh:NavHelper.NavigateTo="shvp:FeedbackPage"
Content="{shcm:ResourceString Name=ViewFeedbackHeader}"
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Feedback.png}"/>
<NavigationViewItemHeader Content="{shcm:ResourceString Name=ViewToolHeader}"/>

View File

@@ -1,258 +0,0 @@
<shc:ScopedPage
x:Class="Snap.Hutao.View.Page.FeedbackPage"
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:cwc="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shvf="using:Snap.Hutao.ViewModel.Feedback"
d:DataContext="{d:DesignInstance shvf:FeedbackViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<mxi:Interaction.Behaviors>
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
</mxi:Interaction.Behaviors>
<Grid>
<SplitView
DisplayMode="Inline"
IsPaneOpen="True"
OpenPaneLength="400"
PaneBackground="{x:Null}"
PanePlacement="Right">
<SplitView.Pane>
<ScrollViewer>
<StackPanel Margin="16" Spacing="3">
<cwc:SettingsExpander
Description="{Binding RuntimeOptions.Version}"
Header="{shcm:ResourceString Name=AppName}"
HeaderIcon="{shcm:FontIcon Glyph=&#xECAA;}"
IsExpanded="True">
<cwc:SettingsExpander.Items>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE8C8;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
Command="{Binding CopyDeviceIdCommand}"
Description="{Binding RuntimeOptions.DeviceId}"
Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}"
IsClickEnabled="True"/>
<cwc:SettingsCard Description="{Binding IPInformation}" Header="{shcm:ResourceString Name=ViewPageSettingDeviceIpHeader}"/>
<cwc:SettingsCard Description="{Binding DynamicHttpProxy.CurrentProxy}" Header="{shcm:ResourceString Name=ViewPageFeedbackCurrentProxyHeader}"/>
<cwc:SettingsCard Description="{Binding RuntimeOptions.WebView2Version}" Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"/>
</cwc:SettingsExpander.Items>
</cwc:SettingsExpander>
<cwc:SettingsExpander
Description="{shcm:ResourceString Name=ViewPageFeedbackEngageWithUsDescription}"
Header="{shcm:ResourceString Name=ViewPageFeedbackCommonLinksHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE71B;}"
IsExpanded="True">
<cwc:SettingsExpander.Items>
<cwc:SettingsCard
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://github.com/DGP-Studio/Snap.Hutao/issues/new/choose"
Description="{shcm:ResourceString Name=ViewPageFeedbackGithubIssuesDescription}"
Header="GitHub Issues"
IsClickEnabled="True"/>
<cwc:SettingsCard
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://github.com/orgs/DGP-Studio/projects/2"
Description="{shcm:ResourceString Name=ViewPageFeedbackRoadmapDescription}"
Header="GitHub Projects"
IsClickEnabled="True"/>
<cwc:SettingsCard
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://status.hut.ao"
Description="{shcm:ResourceString Name=ViewPageFeedbackServerStatusDescription}"
Header="{shcm:ResourceString Name=ViewPageFeedbackServerStatusHeader}"
IsClickEnabled="True"/>
</cwc:SettingsExpander.Items>
</cwc:SettingsExpander>
<cwc:SettingsExpander
Header="{shcm:ResourceString Name=ViewPageFeedbackFeatureGuideHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xF8A5;}"
IsExpanded="True">
<cwc:SettingsExpander.Items>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/dashboard.html"
Header="{shcm:ResourceString Name=ViewAnnouncementHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Announcement.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/game-launcher.html"
Header="{shcm:ResourceString Name=ViewLaunchGameHeader}"
IsClickEnabled="True">
<cwc:SettingsCard.HeaderIcon>
<!-- This icon is not a square -->
<BitmapIcon
Width="24"
Height="24"
ShowAsMonochrome="False"
UriSource="ms-appx:///Resource/Navigation/LaunchGame.png"/>
</cwc:SettingsCard.HeaderIcon>
</cwc:SettingsCard>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/wish-export.html"
Header="{shcm:ResourceString Name=ViewGachaLogHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/GachaLog.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/achievements.html"
Header="{shcm:ResourceString Name=ViewAchievementHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Achievement.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/real-time-notes.html"
Header="{shcm:ResourceString Name=ViewDailyNoteHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/DailyNote.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/character-data.html"
Header="{shcm:ResourceString Name=ViewAvatarPropertyHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/AvatarProperty.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/hutao-API.html"
Header="{shcm:ResourceString Name=ViewSpiralAbyssHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/SpiralAbyss.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/develop-plan.html"
Header="{shcm:ResourceString Name=ViewCultivationHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/Cultivation.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/character-wiki.html"
Header="{shcm:ResourceString Name=ViewWikiAvatarHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiAvatar.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/weapon-wiki.html"
Header="{shcm:ResourceString Name=ViewWikiWeaponHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiWeapon.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/monster-wiki.html"
Header="{shcm:ResourceString Name=ViewWikiMonsterHeader}"
HeaderIcon="{shcm:BitmapIcon Source=ms-appx:///Resource/Navigation/WikiMonster.png}"
IsClickEnabled="True"/>
<cwc:SettingsCard
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
Command="{Binding NavigateToUriCommand}"
CommandParameter="https://hut.ao/features/hutao-settings.html"
Header="{shcm:ResourceString Name=ViewSettingHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE713;}"
IsClickEnabled="True"/>
</cwc:SettingsExpander.Items>
</cwc:SettingsExpander>
</StackPanel>
</ScrollViewer>
</SplitView.Pane>
<Grid>
<Grid
Padding="16,16,0,16"
RowSpacing="8"
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<AutoSuggestBox
Grid.Row="0"
Height="36"
Margin="0,0,0,8"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
PlaceholderText="{shcm:ResourceString Name=ViewPageFeedbackAutoSuggestBoxPlaceholder}"
QueryIcon="{shcm:FontIcon Glyph=&#xE721;}"
Style="{StaticResource DefaultAutoSuggestBoxStyle}"
Text="{Binding SearchText, Mode=TwoWay}">
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
<mxic:InvokeCommandAction Command="{Binding SearchDocumentCommand}" CommandParameter="{Binding SearchText}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</AutoSuggestBox>
<StackPanel
Grid.Row="1"
VerticalAlignment="Center"
Visibility="{Binding SearchResults.Count, Converter={StaticResource Int32ToVisibilityRevertConverter}}">
<shci:CachedImage
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon52}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageFeedbackSearchResultPlaceholderTitle}"/>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
<ItemsControl
ItemContainerTransitions="{ThemeResource ListViewLikeThemeTransitions}"
ItemsPanel="{ThemeResource StackPanelSpacing8Template}"
ItemsSource="{Binding SearchResults}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Style="{ThemeResource BorderCardStyle}">
<HyperlinkButton
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
NavigateUri="{Binding Url}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<BreadcrumbBar
Grid.Column="0"
Margin="4,8,8,4"
IsHitTestVisible="False"
ItemsSource="{Binding Hierarchy.DisplayLevels}"/>
</Grid>
</HyperlinkButton>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
<clw:Shimmer
CornerRadius="0"
IsActive="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityRevertConverter}, Mode=OneWay}"/>
</Grid>
</SplitView>
</Grid>
</shc:ScopedPage>

View File

@@ -1,16 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Control;
using Snap.Hutao.ViewModel.Feedback;
namespace Snap.Hutao.View.Page;
internal sealed partial class FeedbackPage : ScopedPage
{
public FeedbackPage()
{
InitializeWith<FeedbackViewModel>();
InitializeComponent();
}
}

View File

@@ -171,8 +171,8 @@
Text="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeWarning}"/>
</StackPanel>
</cwc:SettingsCard.Description>
<StackPanel Orientation="Horizontal" Spacing="{ThemeResource SettingsCardContentControlSpacing}">
<shvc:Elevation Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<StackPanel Orientation="Horizontal">
<shvc:Elevation Margin="0,0,36,0" Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<shc:SizeRestrictedContentControl>
<shccs:ComboBox2
DisplayMemberPath="DisplayName"
@@ -203,7 +203,7 @@
Description="{shcm:ResourceString Name=ViewPageLaunchGameWindowsHDRDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameWindowsHDRHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE7F7;}">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsWindowsHDREnabled, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsWindowsHDREnabled, Mode=TwoWay}"/>
</cwc:SettingsCard>
<!-- 进程 -->
@@ -213,88 +213,81 @@
Description="{shcm:ResourceString Name=ViewPageLaunchGameArgumentsDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameArgumentsHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE943;}">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsEnabled, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsEnabled, Mode=TwoWay}"/>
<cwc:SettingsExpander.Items>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceExclusiveDescription}" Header="-window-mode exclusive">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsExclusive, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsExclusive, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceFullscreenDescription}" Header="-screen-fullscreen">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsFullScreen, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsFullScreen, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceBorderlessDescription}" Header="-popupwindow">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsBorderless, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsBorderless, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceCloudThirdPartyMobileDescription}" Header="-platform_type CLOUD_THIRD_PARTY_MOBILE">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsUseCloudThirdPartyMobile, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsUseCloudThirdPartyMobile, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceAspectRatioDescription}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceAspectRatioHeader}">
<shc:SizeRestrictedContentControl Margin="0,0,130,0" VerticalAlignment="Center">
<shc:SizeRestrictedContentControl Margin="0,0,136,0">
<ComboBox
MinWidth="{ThemeResource SettingsCardContentControlMinWidth2}"
ItemsSource="{Binding LaunchOptions.AspectRatios}"
PlaceholderText="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceAspectRatioPlaceHolder}"
SelectedItem="{Binding LaunchOptions.SelectedAspectRatio, Mode=TwoWay}"/>
</shc:SizeRestrictedContentControl>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthDescription}" Header="-screen-width">
<StackPanel Orientation="Horizontal" Spacing="10">
<StackPanel Orientation="Horizontal" Spacing="16">
<NumberBox
MinWidth="{ThemeResource SettingsCardContentControlMinWidth2}"
Width="156"
Padding="12,6,0,0"
VerticalAlignment="Center"
IsEnabled="{Binding LaunchOptions.IsScreenWidthEnabled}"
Value="{Binding LaunchOptions.ScreenWidth, Mode=TwoWay}"/>
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsScreenWidthEnabled, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsScreenWidthEnabled, Mode=TwoWay}"/>
</StackPanel>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightDescription}" Header="-screen-height">
<StackPanel Orientation="Horizontal" Spacing="10">
<StackPanel Orientation="Horizontal" Spacing="16">
<NumberBox
MinWidth="{ThemeResource SettingsCardContentControlMinWidth2}"
Width="156"
Padding="12,6,0,0"
VerticalAlignment="Center"
IsEnabled="{Binding LaunchOptions.IsScreenHeightEnabled}"
Value="{Binding LaunchOptions.ScreenHeight, Mode=TwoWay}"/>
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsScreenHeightEnabled, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsScreenHeightEnabled, Mode=TwoWay}"/>
</StackPanel>
</cwc:SettingsCard>
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsDescription}" Header="-monitor">
<StackPanel Orientation="Horizontal" Spacing="10">
<Button
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
Command="{Binding IdentifyMonitorsCommand}"
Content="{shcm:ResourceString Name=ViewModelLaunchGameIdentifyMonitorsAction}"/>
<shc:SizeRestrictedContentControl VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" Spacing="16">
<shc:SizeRestrictedContentControl>
<ComboBox
MinWidth="{ThemeResource SettingsCardContentControlMinWidth2}"
DisplayMemberPath="Name"
IsEnabled="{Binding LaunchOptions.IsMonitorEnabled}"
ItemsSource="{Binding LaunchOptions.Monitors}"
SelectedItem="{Binding LaunchOptions.Monitor, Mode=TwoWay}"/>
</shc:SizeRestrictedContentControl>
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.IsMonitorEnabled, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.IsMonitorEnabled, Mode=TwoWay}"/>
</StackPanel>
</cwc:SettingsCard>
</cwc:SettingsExpander.Items>
</cwc:SettingsExpander>
<cwc:SettingsCard
Padding="{ThemeResource SettingsCardAlignSettingsExpanderPadding}"
Description="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE785;}"
IsEnabled="{Binding RuntimeOptions.IsElevated}"
Visibility="{Binding LaunchOptions.IsAdvancedLaunchOptionsEnabled, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Orientation="Horizontal" Spacing="10">
<shvc:Elevation Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<StackPanel Orientation="Horizontal">
<shvc:Elevation Margin="0,0,36,0" Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<NumberBox
MinWidth="{ThemeResource SettingsCardContentControlMinWidth2}"
MinWidth="156"
Padding="10,8,0,0"
Maximum="720"
Minimum="60"
SpinButtonPlacementMode="Inline"
Value="{Binding LaunchOptions.TargetFps, Mode=TwoWay}"/>
<ToggleSwitch
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
Width="120"
IsOn="{Binding LaunchOptions.UnlockFps, Mode=TwoWay}"
OffContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOff}"
OnContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOn}"/>
@@ -307,13 +300,13 @@
Description="{shcm:ResourceString Name=ViewPageLaunchGamePlayTimeDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGamePlayTimeHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xEC92;}">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.UseStarwardPlayTimeStatistics, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.UseStarwardPlayTimeStatistics, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard
Description="{shcm:ResourceString Name=ViewPageLaunchGameDiscordActivityDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameDiscordActivityHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE8CF;}">
<ToggleSwitch MinWidth="{ThemeResource SettingsCardContentControlMinWidth}" IsOn="{Binding LaunchOptions.SetDiscordActivityWhenPlaying, Mode=TwoWay}"/>
<ToggleSwitch Width="120" IsOn="{Binding LaunchOptions.SetDiscordActivityWhenPlaying, Mode=TwoWay}"/>
</cwc:SettingsCard>
</StackPanel>
</Grid>
@@ -362,8 +355,8 @@
VerticalAlignment="Center"
Spacing="3">
<shci:CachedImage
Width="120"
Height="120"
MinWidth="{ThemeResource SettingsCardContentControlMinWidth}"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon445}"/>
<TextBlock

View File

@@ -97,7 +97,7 @@
Description="{shcm:ResourceString Name=ViewPageSettingElevatedModeDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingElevatedModeRestartAction}"
IsClickEnabled="True"
IsEnabled="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolNegationConverter}}"/>
IsEnabled="{Binding HutaoOptions.IsElevated, Converter={StaticResource BoolNegationConverter}}"/>
<cwc:SettingsCard
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCreateDesktopShortcutAction}"
Command="{Binding CreateDesktopShortcutCommand}"
@@ -111,6 +111,23 @@
</shch:ScrollViewerHelper.RightPanel>
<Grid Padding="16" HorizontalAlignment="Left">
<StackPanel Grid.Column="0" Spacing="{StaticResource SettingsCardSpacing}">
<cwc:SettingsExpander
Description="{Binding HutaoOptions.Version}"
Header="{shcm:ResourceString Name=AppName}"
HeaderIcon="{shcm:FontIcon Glyph=&#xECAA;}"
IsExpanded="True">
<cwc:SettingsExpander.Items>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE8C8;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
Command="{Binding CopyDeviceIdCommand}"
Description="{Binding HutaoOptions.DeviceId}"
Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}"
IsClickEnabled="True"/>
<cwc:SettingsCard Description="{Binding IPInformation}" Header="{shcm:ResourceString Name=ViewPageSettingDeviceIpHeader}"/>
<cwc:SettingsCard Description="{Binding HutaoOptions.WebView2Version}" Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"/>
</cwc:SettingsExpander.Items>
</cwc:SettingsExpander>
<!--
https://github.com/DGP-Studio/Snap.Hutao/issues/1072
ItemsRepeater will behave abnormal if no direct scrollhost wrapping it
@@ -196,7 +213,7 @@
<shc:SizeRestrictedContentControl>
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding CultureOptions.Cultures}"
ItemsSource="{Binding AppOptions.Cultures}"
SelectedItem="{Binding SelectedCulture, Mode=TwoWay}"/>
</shc:SizeRestrictedContentControl>
</cwc:SettingsCard>
@@ -399,7 +416,7 @@
<cwc:SettingsCard
Header="{shcm:ResourceString Name=ViewPageSettingIsAdvancedLaunchOptionsEnabledHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE730;}"
IsEnabled="{Binding RuntimeOptions.IsElevated}">
IsEnabled="{Binding HutaoOptions.IsElevated}">
<cwc:SettingsCard.Description>
<StackPanel>
<TextBlock
@@ -410,7 +427,7 @@
</StackPanel>
</cwc:SettingsCard.Description>
<StackPanel Orientation="Horizontal">
<shvc:Elevation Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<shvc:Elevation Visibility="{Binding HutaoOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<ToggleSwitch Width="120" IsOn="{Binding IsAdvancedLaunchOptionsEnabled, Mode=TwoWay}"/>
</StackPanel>
</cwc:SettingsCard>

View File

@@ -61,6 +61,31 @@
</ResourceDictionary>
</StackPanel.Resources>
<Button
Margin="4,0"
Padding="6,6"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Command="{Binding OpenDocumentationCommand}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<BitmapIcon
Grid.Column="0"
Width="24"
Height="24"
ShowAsMonochrome="False"
UriSource="ms-appx:///Resource/Navigation/Documentation.png"/>
<TextBlock
Grid.Column="1"
Margin="13,0,0,0"
VerticalAlignment="Center"
Text="{shcm:ResourceString Name=ViewUserDocumentationHeader}"/>
</Grid>
</Button>
<Button MaxHeight="40" Margin="4,0">
<Button.Content>
<Grid>

View File

@@ -1,116 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.IO.DataTransfer;
using Snap.Hutao.Core.IO.Http.DynamicProxy;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Web.Hutao;
using Snap.Hutao.Web.Hutao.Algolia;
using Snap.Hutao.Web.Response;
using System.Runtime.InteropServices;
using Windows.System;
namespace Snap.Hutao.ViewModel.Feedback;
[Injection(InjectAs.Scoped)]
[ConstructorGenerated]
internal sealed partial class FeedbackViewModel : Abstraction.ViewModel
{
private readonly HutaoInfrastructureClient hutaoInfrastructureClient;
private readonly HutaoDocumentationClient hutaoDocumentationClient;
private readonly IClipboardProvider clipboardProvider;
private readonly DynamicHttpProxy dynamicHttpProxy;
private readonly IInfoBarService infoBarService;
private readonly CultureOptions cultureOptions;
private readonly RuntimeOptions runtimeOptions;
private readonly ITaskContext taskContext;
private string? searchText;
private List<AlgoliaHit>? searchResults;
private IPInformation? ipInformation;
public RuntimeOptions RuntimeOptions { get => runtimeOptions; }
public DynamicHttpProxy DynamicHttpProxy { get => dynamicHttpProxy; }
public string? SearchText { get => searchText; set => SetProperty(ref searchText, value); }
public List<AlgoliaHit>? SearchResults { get => searchResults; set => SetProperty(ref searchResults, value); }
public IPInformation? IPInformation { get => ipInformation; private set => SetProperty(ref ipInformation, value); }
protected override async ValueTask<bool> InitializeUIAsync()
{
Response<IPInformation> resp = await hutaoInfrastructureClient.GetIPInformationAsync().ConfigureAwait(false);
IPInformation info;
if (resp.IsOk())
{
info = resp.Data;
}
else
{
info = IPInformation.Default;
}
await taskContext.SwitchToMainThreadAsync();
IPInformation = info;
return true;
}
[Command("NavigateToUriCommand")]
private static async Task NavigateToUri(string? uri)
{
if (string.IsNullOrEmpty(uri))
{
return;
}
await Launcher.LaunchUriAsync(uri.ToUri());
}
[Command("SearchDocumentCommand")]
private async Task SearchDocumentAsync(string? searchText)
{
IsInitialized = false;
SearchResults = null;
if (string.IsNullOrEmpty(searchText))
{
IsInitialized = true;
return;
}
string language = cultureOptions.GetLanguageCodeForDocumentationSearch();
AlgoliaResponse? response = await hutaoDocumentationClient.QueryAsync(searchText, language).ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
if (response is { Results: [AlgoliaResult { Hits: { Count: > 0 } hits }, ..] })
{
SearchResults = [.. hits.DistinctBy(hit => hit.Url)];
}
else
{
SearchResults = null;
}
IsInitialized = true;
}
[Command("CopyDeviceIdCommand")]
private void CopyDeviceId()
{
try
{
clipboardProvider.SetText(RuntimeOptions.DeviceId);
infoBarService.Success(SH.ViewModelSettingCopyDeviceIdSuccess);
}
catch (COMException ex)
{
infoBarService.Error(ex);
}
}
}

View File

@@ -13,9 +13,17 @@ internal static class LaunchGameShared
{
public static LaunchScheme? GetCurrentLaunchSchemeFromConfigFile(IGameServiceFacade gameService, IInfoBarService infoBarService)
{
ChannelOptions options = gameService.GetChannelOptions();
ChannelOptions options;
try
{
options = gameService.GetChannelOptions();
}
catch (InvalidOperationException)
{
return default;
}
if (options.ErrorKind is ChannelOptionsErrorKind.None)
if (string.IsNullOrEmpty(options.ConfigFilePath))
{
try
{
@@ -32,7 +40,7 @@ internal static class LaunchGameShared
}
else
{
infoBarService.Warning($"{options.ErrorKind}", SH.FormatViewModelLaunchGameMultiChannelReadFail(options.FilePath));
infoBarService.Warning(SH.FormatViewModelLaunchGameMultiChannelReadFail(options.ConfigFilePath));
}
return default;

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.WinUI.Collections;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Windowing;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Diagnostics.CodeAnalysis;
using Snap.Hutao.Core.ExceptionService;
@@ -339,28 +338,4 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
};
}
}
[Command("IdentifyMonitorsCommand")]
private async Task IdentifyMonitorsAsync()
{
List<IdentifyMonitorWindow> windows = [];
IReadOnlyList<DisplayArea> displayAreas = DisplayArea.FindAll();
for (int i = 0; i < displayAreas.Count; i++)
{
windows.Add(new IdentifyMonitorWindow(displayAreas[i], i + 1));
}
foreach (IdentifyMonitorWindow window in windows)
{
window.Activate();
}
await Delay.FromSeconds(3).ConfigureAwait(true);
foreach (IdentifyMonitorWindow window in windows)
{
window.Close();
}
}
}

View File

@@ -37,8 +37,8 @@ internal sealed class DownloadSummary : ObservableObject
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
httpClient = serviceProvider.GetRequiredService<HttpClient>();
imageCache = serviceProvider.GetRequiredService<IImageCache>();
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(runtimeOptions.UserAgent);
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
this.serviceProvider = serviceProvider;

View File

@@ -20,7 +20,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
{
private readonly IServiceProvider serviceProvider;
private readonly ITaskContext taskContext;
private readonly CultureOptions cultureOptions;
private readonly AppOptions appOptions;
private readonly RuntimeOptions runtimeOptions;
private string nextOrCompleteButtonText = SH.ViewModelGuideActionNext;
@@ -75,18 +75,18 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
public bool IsNextOrCompleteButtonEnabled { get => isNextOrCompleteButtonEnabled; set => SetProperty(ref isNextOrCompleteButtonEnabled, value); }
public CultureOptions CultureOptions { get => cultureOptions; }
public AppOptions AppOptions { get => appOptions; }
public RuntimeOptions RuntimeOptions { get => runtimeOptions; }
public NameValue<CultureInfo>? SelectedCulture
{
get => selectedCulture ??= CultureOptions.GetCurrentCultureForSelectionOrDefault();
get => selectedCulture ??= AppOptions.GetCurrentCultureForSelectionOrDefault();
set
{
if (SetProperty(ref selectedCulture, value) && value is not null)
{
CultureOptions.CurrentCulture = value.Value;
AppOptions.CurrentCulture = value.Value;
++State;
AppInstance.Restart(string.Empty);
}

View File

@@ -24,8 +24,8 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
private readonly IHutaoAsAService hutaoAsAService;
private readonly IAnnouncementService announcementService;
private readonly HutaoUserOptions hutaoUserOptions;
private readonly CultureOptions cultureOptions;
private readonly ITaskContext taskContext;
private readonly MetadataOptions metadataOptions;
private readonly AppOptions appOptions;
private AnnouncementWrapper? announcement;
@@ -65,7 +65,7 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
{
try
{
AnnouncementWrapper announcementWrapper = await announcementService.GetAnnouncementWrapperAsync(cultureOptions.LanguageCode, appOptions.Region, CancellationToken).ConfigureAwait(false);
AnnouncementWrapper announcementWrapper = await announcementService.GetAnnouncementWrapperAsync(metadataOptions.LanguageCode, appOptions.Region, CancellationToken).ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
Announcement = announcementWrapper;
}

View File

@@ -26,7 +26,18 @@ internal sealed partial class FolderViewModel : ObservableObject
public string? Size { get => size; set => SetProperty(ref size, value); }
public async ValueTask SetFolderSizeAsync()
public async ValueTask RefreshFolderSizeAsync()
{
await SetFolderSizeAsync().ConfigureAwait(false);
}
[Command("OpenFolderCommand")]
private async Task OpenDataFolderAsync()
{
await Launcher.LaunchFolderPathAsync(folder);
}
private async ValueTask SetFolderSizeAsync()
{
await taskContext.SwitchToBackgroundAsync();
long totalSize = 0;
@@ -39,10 +50,4 @@ internal sealed partial class FolderViewModel : ObservableObject
await taskContext.SwitchToMainThreadAsync();
Size = SH.FormatViewModelSettingFolderSizeDescription(Converters.ToFileSizeString(totalSize));
}
[Command("OpenFolderCommand")]
private async Task OpenDataFolderAsync()
{
await Launcher.LaunchFolderPathAsync(folder);
}
}

View File

@@ -43,13 +43,14 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
private readonly HomeCardOptions homeCardOptions = new();
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
private readonly HutaoInfrastructureClient hutaoInfrastructureClient;
private readonly HutaoPassportViewModel hutaoPassportViewModel;
private readonly IContentDialogFactory contentDialogFactory;
private readonly INavigationService navigationService;
private readonly IClipboardProvider clipboardInterop;
private readonly IShellLinkInterop shellLinkInterop;
private readonly HutaoUserOptions hutaoUserOptions;
private readonly IInfoBarService infoBarService;
private readonly CultureOptions cultureOptions;
private readonly RuntimeOptions runtimeOptions;
private readonly LaunchOptions launchOptions;
private readonly HotKeyOptions hotKeyOptions;
@@ -60,14 +61,13 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
private NameValue<BackdropType>? selectedBackdropType;
private NameValue<CultureInfo>? selectedCulture;
private NameValue<Region>? selectedRegion;
private IPInformation? ipInformation;
private FolderViewModel? cacheFolderView;
private FolderViewModel? dataFolderView;
public AppOptions AppOptions { get => appOptions; }
public CultureOptions CultureOptions { get => cultureOptions; }
public RuntimeOptions RuntimeOptions { get => runtimeOptions; }
public RuntimeOptions HutaoOptions { get => runtimeOptions; }
public HutaoUserOptions UserOptions { get => hutaoUserOptions; }
@@ -93,12 +93,12 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
public NameValue<CultureInfo>? SelectedCulture
{
get => selectedCulture ??= CultureOptions.GetCurrentCultureForSelectionOrDefault();
get => selectedCulture ??= AppOptions.GetCurrentCultureForSelectionOrDefault();
set
{
if (SetProperty(ref selectedCulture, value) && value is not null)
{
CultureOptions.CurrentCulture = value.Value;
AppOptions.CurrentCulture = value.Value;
AppInstance.Restart(string.Empty);
}
}
@@ -120,6 +120,8 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
public FolderViewModel? DataFolderView { get => dataFolderView; set => SetProperty(ref dataFolderView, value); }
public IPInformation? IPInformation { get => ipInformation; private set => SetProperty(ref ipInformation, value); }
public bool IsAllocConsoleDebugModeEnabled
{
get => LocalSetting.Get(SettingKeys.IsAllocConsoleDebugModeEnabled, false);
@@ -172,12 +174,27 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
}
}
protected override ValueTask<bool> InitializeUIAsync()
protected override async ValueTask<bool> InitializeUIAsync()
{
CacheFolderView = new(taskContext, runtimeOptions.LocalCache);
DataFolderView = new(taskContext, runtimeOptions.DataFolder);
return ValueTask.FromResult(true);
Response<IPInformation> resp = await hutaoInfrastructureClient.GetIPInformationAsync().ConfigureAwait(false);
IPInformation info;
if (resp.IsOk())
{
info = resp.Data;
}
else
{
info = IPInformation.Default;
}
await taskContext.SwitchToMainThreadAsync();
IPInformation = info;
return true;
}
[Command("ResetStaticResourceCommand")]
@@ -267,15 +284,25 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
Directory.Delete(cacheFolder, true);
}
if (DataFolderView is not null)
{
await DataFolderView.SetFolderSizeAsync().ConfigureAwait(false);
}
DataFolderView?.RefreshFolderSizeAsync().SafeForget();
infoBarService.Information(SH.ViewModelSettingActionComplete);
}
}
[Command("CopyDeviceIdCommand")]
private void CopyDeviceId()
{
try
{
clipboardInterop.SetText(HutaoOptions.DeviceId);
infoBarService.Success(SH.ViewModelSettingCopyDeviceIdSuccess);
}
catch (COMException ex)
{
infoBarService.Error(ex);
}
}
[Command("DeleteUsersCommand")]
private async Task DangerousDeleteUsersAsync()
{

View File

@@ -32,6 +32,7 @@ namespace Snap.Hutao.ViewModel.User;
internal sealed partial class UserViewModel : ObservableObject
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly IDocumentationProvider documentationProvider;
private readonly INavigationService navigationService;
private readonly IServiceProvider serviceProvider;
private readonly IInfoBarService infoBarService;
@@ -279,4 +280,10 @@ internal sealed partial class UserViewModel : ObservableObject
FlyoutBase.ShowAttachedFlyout(appBarButton);
infoBarService.Warning(message);
}
[Command("OpenDocumentationCommand")]
private async Task OpenDocumentationAsync()
{
await Launcher.LaunchUriAsync(new(documentationProvider.GetDocumentation()));
}
}

View File

@@ -4,7 +4,6 @@
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core.DependencyInjection.Abstraction;
using Snap.Hutao.Core.IO.DataTransfer;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
@@ -184,13 +183,13 @@ internal class MiHoYoJSBridge
protected virtual JsResult<Dictionary<string, string>> GetCurrentLocale(JsParam<PushPagePayload> param)
{
CultureOptions cultureOptions = serviceProvider.GetRequiredService<CultureOptions>();
MetadataOptions metadataOptions = serviceProvider.GetRequiredService<MetadataOptions>();
return new()
{
Data = new()
{
["language"] = cultureOptions.LanguageCode,
["language"] = metadataOptions.LanguageCode,
["timeZone"] = "GMT+8",
},
};

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab.DataSigning;
@@ -24,14 +23,14 @@ internal sealed partial class SignInClient : ISignInClient
{
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
private readonly HomaGeetestClient homaGeetestClient;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
private readonly ILogger<SignInClient> logger;
private readonly HttpClient httpClient;
public async ValueTask<Response<ExtraAwardInfo>> GetExtraAwardInfoAsync(UserAndUid userAndUid, CancellationToken token = default)
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(ApiEndpoints.LunaExtraAward(userAndUid.Uid, cultureOptions.LanguageCode))
.SetRequestUri(ApiEndpoints.LunaExtraAward(userAndUid.Uid, metadataOptions.LanguageCode))
.SetUserCookieAndFpHeader(userAndUid, CookieType.CookieToken)
.SetHeader("x-rpc-signgame", "hk4e")
.Get();
@@ -48,7 +47,7 @@ internal sealed partial class SignInClient : ISignInClient
public async ValueTask<Response<SignInRewardInfo>> GetInfoAsync(UserAndUid userAndUid, CancellationToken token = default)
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(ApiEndpoints.LunaInfo(userAndUid.Uid, cultureOptions.LanguageCode))
.SetRequestUri(ApiEndpoints.LunaInfo(userAndUid.Uid, metadataOptions.LanguageCode))
.SetUserCookieAndFpHeader(userAndUid, CookieType.CookieToken)
.SetHeader("x-rpc-signgame", "hk4e")
.Get();
@@ -82,7 +81,7 @@ internal sealed partial class SignInClient : ISignInClient
public async ValueTask<Response<Reward>> GetRewardAsync(Model.Entity.User user, CancellationToken token = default)
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(ApiEndpoints.LunaHome(cultureOptions.LanguageCode))
.SetRequestUri(ApiEndpoints.LunaHome(metadataOptions.LanguageCode))
.SetUserCookieAndFpHeader(user, CookieType.CookieToken)
.SetHeader("x-rpc-signgame", "hk4e")
.Get();

View File

@@ -1,77 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaHierarchy
{
[JsonPropertyName("lvl1")]
public string? Lvl1 { get; set; }
[JsonPropertyName("lvl2")]
public string? Lvl2 { get; set; }
[JsonPropertyName("lvl3")]
public string? Lvl3 { get; set; }
[JsonPropertyName("lvl4")]
public string? Lvl4 { get; set; }
[JsonPropertyName("lvl5")]
public string? Lvl5 { get; set; }
[JsonPropertyName("lvl6")]
public string? Lvl6 { get; set; }
public IEnumerable<string> DisplayLevels
{
get
{
return GetDisplayLevels();
IEnumerable<string> GetDisplayLevels()
{
if (string.IsNullOrEmpty(Lvl1))
{
yield break;
}
yield return Lvl1;
if (string.IsNullOrEmpty(Lvl2))
{
yield break;
}
yield return Lvl2;
if (string.IsNullOrEmpty(Lvl3))
{
yield break;
}
yield return Lvl3;
if (string.IsNullOrEmpty(Lvl4))
{
yield break;
}
yield return Lvl4;
if (string.IsNullOrEmpty(Lvl5))
{
yield break;
}
yield return Lvl5;
if (string.IsNullOrEmpty(Lvl6))
{
yield break;
}
yield return Lvl6;
}
}
}
}

View File

@@ -1,13 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaHit
{
[JsonPropertyName("url")]
public string Url { get; set; } = default!;
[JsonPropertyName("hierarchy")]
public AlgoliaHierarchy Hierarchy { get; set; } = default!;
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaRequest
{
[JsonPropertyName("query")]
public string Query { get; set; } = default!;
[JsonPropertyName("indexName")]
public string IndexName { get; set; } = default!;
[JsonPropertyName("params")]
public string Params { get; set; } = default!;
}

View File

@@ -1,10 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaRequestsWrapper
{
[JsonPropertyName("requests")]
public List<AlgoliaRequest> Requests { get; set; } = default!;
}

View File

@@ -1,9 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaResponse
{
public List<AlgoliaResult> Results { get; set; } = default!;
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Hutao.Algolia;
internal sealed class AlgoliaResult
{
[JsonPropertyName("hits")]
public List<AlgoliaHit> Hits { get; set; } = default!;
}

View File

@@ -1,46 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Hutao.Algolia;
[HttpClient(HttpClientConfiguration.Default)]
[ConstructorGenerated(ResolveHttpClient = true)]
internal sealed partial class HutaoDocumentationClient
{
private const string AlgoliaApiKey = "72d7a9a0f9f0466218ea19988886dce8";
private const string AlgoliaApplicationId = "28CTGDOOQD";
private const string AlgolianetIndexesQueries = $"https://28ctgdooqd-1.algolianet.com/1/indexes/*/queries";
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
private readonly ILogger<HutaoDocumentationClient> logger;
private readonly HttpClient httpClient;
public async ValueTask<AlgoliaResponse?> QueryAsync(string query, string language, CancellationToken token = default)
{
AlgoliaRequestsWrapper data = new()
{
Requests =
[
new AlgoliaRequest
{
Query = query,
IndexName = "hutao",
Params = $"""facetFilters=["lang:{language}"]""",
},
],
};
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(AlgolianetIndexesQueries)
.SetHeader("x-algolia-api-key", AlgoliaApiKey)
.SetHeader("x-algolia-application-id", AlgoliaApplicationId)
.PostJson(data);
return await builder.TryCatchSendAsync<AlgoliaResponse>(httpClient, logger, token).ConfigureAwait(false);
}
}

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Web.Hutao.Response;
@@ -22,13 +21,13 @@ internal sealed partial class HutaoAsAServiceClient
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
private readonly ILogger<HutaoAsAServiceClient> logger;
private readonly HutaoUserOptions hutaoUserOptions;
private readonly CultureOptions cultureOptions;
private readonly MetadataOptions metadataOptions;
private readonly HttpClient httpClient;
public async ValueTask<HutaoResponse<List<Announcement>>> GetAnnouncementListAsync(List<long> excluedeIds, CancellationToken token = default)
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(HutaoEndpoints.Announcement(cultureOptions.LocaleName))
.SetRequestUri(HutaoEndpoints.Announcement(metadataOptions.LocaleName))
.PostJson(excluedeIds);
HutaoResponse<List<Announcement>>? resp = await builder

View File

@@ -130,11 +130,6 @@ internal enum KnownReturnCode
/// </summary>
CODE1034 = 1034,
/// <summary>
/// Hoyolab 登录失败
/// </summary>
SignInError = 2001,
/// <summary>
/// 实时便笺 当前账号存在风险,暂无数据
/// </summary>

View File

@@ -1,155 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
using Windows.Win32.System.Registry;
using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Win32.Registry;
internal sealed partial class RegistryWatcher : IDisposable
{
private const REG_SAM_FLAGS RegSamFlags =
REG_SAM_FLAGS.KEY_QUERY_VALUE |
REG_SAM_FLAGS.KEY_NOTIFY |
REG_SAM_FLAGS.KEY_READ;
private const REG_NOTIFY_FILTER RegNotifyFilters =
REG_NOTIFY_FILTER.REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_FILTER.REG_NOTIFY_CHANGE_ATTRIBUTES |
REG_NOTIFY_FILTER.REG_NOTIFY_CHANGE_LAST_SET |
REG_NOTIFY_FILTER.REG_NOTIFY_CHANGE_SECURITY;
private readonly ManualResetEvent disposeEvent = new(false);
private readonly CancellationTokenSource cancellationTokenSource = new();
private readonly HKEY hKey;
private readonly string subKey = default!;
private readonly Action valueChangedCallback;
private readonly object syncRoot = new();
private bool disposed;
public RegistryWatcher(string keyName, Action valueChangedCallback)
{
string[] pathArray = keyName.Split('\\');
hKey = pathArray[0] switch
{
nameof(HKEY.HKEY_CLASSES_ROOT) => HKEY.HKEY_CLASSES_ROOT,
nameof(HKEY.HKEY_CURRENT_USER) => HKEY.HKEY_CURRENT_USER,
nameof(HKEY.HKEY_LOCAL_MACHINE) => HKEY.HKEY_LOCAL_MACHINE,
nameof(HKEY.HKEY_USERS) => HKEY.HKEY_USERS,
nameof(HKEY.HKEY_CURRENT_CONFIG) => HKEY.HKEY_CURRENT_CONFIG,
_ => throw new ArgumentException("The registry hive '" + pathArray[0] + "' is not supported", nameof(keyName)),
};
subKey = string.Join("\\", pathArray[1..]);
this.valueChangedCallback = valueChangedCallback;
}
public void Start()
{
ObjectDisposedException.ThrowIf(disposed, this);
WatchAsync(cancellationTokenSource.Token).SafeForget();
}
public void Dispose()
{
// Standard no-reentrancy pattern
if (disposed)
{
return;
}
lock (syncRoot)
{
if (disposed)
{
return;
}
// First cancel the outer while loop
cancellationTokenSource.Cancel();
// Then signal the inner while loop to exit
disposeEvent.Set();
// Wait for both loops to exit
disposeEvent.WaitOne();
disposeEvent.Dispose();
cancellationTokenSource.Dispose();
disposed = true;
GC.SuppressFinalize(this);
}
}
[SuppressMessage("", "SH002")]
private static unsafe void UnsafeRegOpenKeyEx(HKEY hKey, string subKey, uint ulOptions, REG_SAM_FLAGS samDesired, out HKEY result)
{
fixed (HKEY* resultPtr = &result)
{
HRESULT hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, subKey, ulOptions, samDesired, resultPtr));
Marshal.ThrowExceptionForHR(hResult);
}
}
[SuppressMessage("", "SH002")]
private static unsafe void UnsafeRegNotifyChangeKeyValue(HKEY hKey, BOOL bWatchSubtree, REG_NOTIFY_FILTER dwNotifyFilter, HANDLE hEvent, BOOL fAsynchronous)
{
HRESULT hRESULT = HRESULT_FROM_WIN32(RegNotifyChangeKeyValue(hKey, bWatchSubtree, dwNotifyFilter, hEvent, fAsynchronous));
Marshal.ThrowExceptionForHR(hRESULT);
}
private async ValueTask WatchAsync(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
UnsafeRegOpenKeyEx(hKey, subKey, 0, RegSamFlags, out HKEY registryKey);
using (ManualResetEvent notifyEvent = new(false))
{
HANDLE hEvent = (HANDLE)notifyEvent.SafeWaitHandle.DangerousGetHandle();
try
{
// If terminateEvent is signaled, the Dispose method
// has been called and the object is shutting down.
// The outer token has already canceled, so we can
// skip both loops and exit the method.
while (!disposeEvent.WaitOne(0, true))
{
UnsafeRegNotifyChangeKeyValue(registryKey, true, RegNotifyFilters, hEvent, true);
if (WaitHandle.WaitAny([notifyEvent, disposeEvent]) is 0)
{
valueChangedCallback();
notifyEvent.Reset();
}
}
}
finally
{
RegCloseKey(registryKey);
}
}
}
if (!disposed)
{
// Before exiting, signal the Dispose method.
disposeEvent.Reset();
}
}
catch (OperationCanceledException)
{
}
}
}