mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
85 Commits
feat/dynam
...
feat/combo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cef1ad3a66 | ||
|
|
d5551e5cdf | ||
|
|
f016a4a27f | ||
|
|
8b931b6d89 | ||
|
|
b942ceb914 | ||
|
|
f7a49e52e0 | ||
|
|
d4bd610fe2 | ||
|
|
a3dcfd3804 | ||
|
|
592525d149 | ||
|
|
83c4598df5 | ||
|
|
aa680388ad | ||
|
|
ba4f59de30 | ||
|
|
8780cf385e | ||
|
|
431cdd1253 | ||
|
|
9a8827fb40 | ||
|
|
d88a6ca301 | ||
|
|
5d401794e5 | ||
|
|
26396443dc | ||
|
|
6b755d934d | ||
|
|
7d5b057269 | ||
|
|
917c173eb2 | ||
|
|
28d702422e | ||
|
|
7612ab5da3 | ||
|
|
ab436ecb2f | ||
|
|
457e3ff4d5 | ||
|
|
224c4e52ea | ||
|
|
2a5c7b21fd | ||
|
|
53f8291a66 | ||
|
|
b621d5406a | ||
|
|
12f4847aea | ||
|
|
39a3d31f38 | ||
|
|
70ac0b13a5 | ||
|
|
a3520a4991 | ||
|
|
aed0284e4b | ||
|
|
96ef07cbe5 | ||
|
|
d1f37f37ac | ||
|
|
1fe09f3069 | ||
|
|
32d9355c3a | ||
|
|
71f170d51e | ||
|
|
60015b6354 | ||
|
|
eecae3ea4f | ||
|
|
1831166f1e | ||
|
|
a98915ea24 | ||
|
|
0d46656f57 | ||
|
|
c814a5c28f | ||
|
|
9c3d59cc6f | ||
|
|
890cf3f3ea | ||
|
|
196bbb54c3 | ||
|
|
0481b9e474 | ||
|
|
c4f3eb68e8 | ||
|
|
c2e9f3a926 | ||
|
|
fb1fe3e40f | ||
|
|
75ed512e4a | ||
|
|
dd4dd33d93 | ||
|
|
1e216e9823 | ||
|
|
f823cb5f1a | ||
|
|
2c6d25f0a3 | ||
|
|
817f768263 | ||
|
|
2998fbb167 | ||
|
|
8f0f94054d | ||
|
|
17a5d4d3a2 | ||
|
|
a1c604e68a | ||
|
|
948ec9a822 | ||
|
|
f83174d690 | ||
|
|
d686debbfb | ||
|
|
45248d75e1 | ||
|
|
22646cfab2 | ||
|
|
d0237a3c89 | ||
|
|
73c80fad10 | ||
|
|
320bed9fcb | ||
|
|
bb12aca3b4 | ||
|
|
c7b5d98fb1 | ||
|
|
7cc96f94f2 | ||
|
|
b35355f9a3 | ||
|
|
745815657d | ||
|
|
d93a9f41f3 | ||
|
|
910f099c6d | ||
|
|
e68449ec0c | ||
|
|
e484fbed21 | ||
|
|
88af6d28a9 | ||
|
|
3ab34f0992 | ||
|
|
5e875a7f18 | ||
|
|
89d98748e8 | ||
|
|
d33cd894b9 | ||
|
|
f0c19b419e |
4
.github/ISSUE_TEMPLATE/CHS-bug-report.yml
vendored
4
.github/ISSUE_TEMPLATE/CHS-bug-report.yml
vendored
@@ -51,7 +51,7 @@ body:
|
||||
description: |
|
||||
在胡桃工具箱的设置界面,你可以找到并复制你的设备 ID
|
||||
如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题
|
||||
如果你的程序已经无法启动,请下载并运行[此工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
|
||||
如果你的程序已经无法启动,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@@ -87,7 +87,7 @@ body:
|
||||
label: 发生了什么?
|
||||
description: |
|
||||
详细的描述问题发生前后的行为,以便我们解决问题。**如果你的问题涉及程序崩溃,你应当检查 Windows 事件查看器,并将相关的 `.Net 错误`详情附上**
|
||||
如果你无法找到该日志,请下载并运行[此工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将转储问题日志至工具运行目录中的 `Snap.Hutao Error Log.txt`
|
||||
如果你无法找到该日志,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将转储问题日志至工具运行目录中的 `Snap.Hutao Error Log.txt`
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/ENG-bug-report.yml
vendored
4
.github/ISSUE_TEMPLATE/ENG-bug-report.yml
vendored
@@ -51,7 +51,7 @@ body:
|
||||
description: |
|
||||
In Snap Hutao's settings page, you can find and copy your device ID
|
||||
If your issue is about program crash, please fill this so we can dump the log and locate the source easier
|
||||
If your program cannot startup, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will shows your device ID.
|
||||
If your program cannot startup, please download and run [Diagnosis Tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will shows your device ID.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@@ -87,7 +87,7 @@ body:
|
||||
label: What Happened?
|
||||
description: |
|
||||
Describe your issue in detail to help us identify the issue. **If your issue is about program crash, you should check Windows Event Viewer, and attach associated `.Net Error` details here**If your program cannot startup, please download and run [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1), it will shows your device ID.
|
||||
If you cannot find it, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will dump the error log to `Snap.Hutao Error Log.txt` in the working directory of the tool.
|
||||
If you cannot find it, please download and run [Diagnosis Tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will dump the error log to `Snap.Hutao Error Log.txt` in the working directory of the tool.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ release:
|
||||
- name: "$THIS_SHA256SUMS_NAME"
|
||||
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/$THIS_SHA256SUMS_NAME?inline=false"
|
||||
link_type: other
|
||||
- name: "artifact_archive"
|
||||
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/download?file_type=archive"
|
||||
link_type: other
|
||||
|
||||
Refresh:
|
||||
stage: refresh
|
||||
|
||||
@@ -44,9 +44,7 @@ Install with Snap Hutao MSIX package, can be installed with Windows built-in App
|
||||
|
||||
### 特定的原神项目 / Specific Genshin-related Projects
|
||||
|
||||
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
|
||||
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
|
||||
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
|
||||
* [Scighost/Starward](https://github.com/Scighost/Starward)
|
||||
|
||||
### 使用的技术栈 / Tech Stack
|
||||
|
||||
@@ -57,7 +55,6 @@ Install with Snap Hutao MSIX package, can be installed with Windows built-in App
|
||||
* [dotnet/efcore](https://github.com/dotnet/efcore)
|
||||
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
||||
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
||||
* [microsoft/CsWin32](https://github.com/microsoft/CsWin32)
|
||||
* [microsoft/vs-validation](https://github.com/microsoft/vs-validation)
|
||||
* [microsoft/WindowsAppSDK](https://github.com/microsoft/WindowsAppSDK)
|
||||
* [microsoft/microsoft-ui-xaml](https://github.com/microsoft/microsoft-ui-xaml)
|
||||
|
||||
@@ -160,9 +160,39 @@ public sealed class GeniusInvokationDecoding
|
||||
|
||||
ushort[] testKnownResult =
|
||||
[
|
||||
060, 019, 001, 079, 120, 120, 129, 151, 151, 153, 153,
|
||||
181, 184, 184, 185, 185, 194, 194, 200, 200, 201, 201,
|
||||
217, 217, 219, 241, 241, 244, 244, 245, 245, 270, 270,
|
||||
060,
|
||||
019,
|
||||
001,
|
||||
079,
|
||||
120,
|
||||
120,
|
||||
129,
|
||||
151,
|
||||
151,
|
||||
153,
|
||||
153,
|
||||
181,
|
||||
184,
|
||||
184,
|
||||
185,
|
||||
185,
|
||||
194,
|
||||
194,
|
||||
200,
|
||||
200,
|
||||
201,
|
||||
201,
|
||||
217,
|
||||
217,
|
||||
219,
|
||||
241,
|
||||
241,
|
||||
244,
|
||||
244,
|
||||
245,
|
||||
245,
|
||||
270,
|
||||
270,
|
||||
];
|
||||
|
||||
CollectionAssert.AreEqual(resultArray, testKnownResult);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/CsWin32/main/src/Microsoft.Windows.CsWin32/settings.schema.json",
|
||||
"allowMarshaling": true,
|
||||
"useSafeHandles": false,
|
||||
"comInterop": {
|
||||
"preserveSigMethods": [
|
||||
"IFileOpenDialog.Show",
|
||||
"IFileSaveDialog.Show"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
// ADVAPI32
|
||||
RegCloseKey
|
||||
RegOpenKeyExW
|
||||
RegNotifyChangeKeyValue
|
||||
REG_NOTIFY_FILTER
|
||||
HKEY_CLASSES_ROOT
|
||||
HKEY_CURRENT_USER
|
||||
HKEY_LOCAL_MACHINE
|
||||
HKEY_USERS
|
||||
HKEY_CURRENT_CONFIG
|
||||
|
||||
// COMCTL32
|
||||
DefSubclassProc
|
||||
RemoveWindowSubclass
|
||||
SetWindowSubclass
|
||||
|
||||
// DWMAPI
|
||||
DwmSetWindowAttribute
|
||||
|
||||
// GDI32
|
||||
GetDeviceCaps
|
||||
|
||||
// KERNEL32
|
||||
AllocConsole
|
||||
CloseHandle
|
||||
CreateEventW
|
||||
CreateRemoteThread
|
||||
FreeConsole
|
||||
GetConsoleMode
|
||||
GetModuleHandleW
|
||||
GetProcAddress
|
||||
GetStdHandle
|
||||
K32EnumProcessModules
|
||||
K32GetModuleBaseNameW
|
||||
K32GetModuleInformation
|
||||
ReadProcessMemory
|
||||
SetConsoleMode
|
||||
SetConsoleTitle
|
||||
SetEvent
|
||||
VirtualAlloc
|
||||
VirtualAllocEx
|
||||
VirtualFree
|
||||
VirtualFreeEx
|
||||
WaitForSingleObject
|
||||
WriteProcessMemory
|
||||
|
||||
// OLE32
|
||||
CoCreateInstance
|
||||
CoWaitForMultipleObjects
|
||||
|
||||
// SHELL32
|
||||
SHCreateItemFromParsingName
|
||||
|
||||
// USER32
|
||||
AttachThreadInput
|
||||
FindWindowExW
|
||||
GetCursorPos
|
||||
GetDC
|
||||
GetDpiForWindow
|
||||
GetForegroundWindow
|
||||
GetWindowLongPtrW
|
||||
GetWindowPlacement
|
||||
GetWindowThreadProcessId
|
||||
ReleaseDC
|
||||
RegisterHotKey
|
||||
SendInput
|
||||
SetForegroundWindow
|
||||
SetWindowLongPtrW
|
||||
UnregisterHotKey
|
||||
|
||||
// COM
|
||||
FileOpenDialog
|
||||
FileSaveDialog
|
||||
IFileOpenDialog
|
||||
IFileSaveDialog
|
||||
IPersistFile
|
||||
IShellLinkDataList
|
||||
IShellLinkW
|
||||
ShellLink
|
||||
SHELL_LINK_DATA_FLAGS
|
||||
|
||||
// WinRT
|
||||
IMemoryBufferByteAccess
|
||||
|
||||
// Const value
|
||||
E_FAIL
|
||||
INFINITE
|
||||
RPC_E_WRONG_THREAD
|
||||
MAX_PATH
|
||||
WM_ERASEBKGND
|
||||
WM_GETMINMAXINFO
|
||||
WM_HOTKEY
|
||||
WM_NCRBUTTONDOWN
|
||||
WM_NCRBUTTONUP
|
||||
WM_NULL
|
||||
|
||||
// Type & Enum definition
|
||||
HRESULT_FROM_WIN32
|
||||
SLGP_FLAGS
|
||||
|
||||
// System.Threading
|
||||
LPTHREAD_START_ROUTINE
|
||||
|
||||
// UI.WindowsAndMessaging
|
||||
MINMAXINFO
|
||||
WINDOW_EX_STYLE
|
||||
|
||||
// System.Com
|
||||
CWMO_FLAGS
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
|
||||
namespace Windows.Win32;
|
||||
|
||||
internal static partial class PInvoke
|
||||
{
|
||||
/// <inheritdoc cref="CoCreateInstance(Guid*, object, CLSCTX, Guid*, out object)"/>
|
||||
internal static unsafe HRESULT CoCreateInstance<TClass, TInterface>(object? pUnkOuter, CLSCTX dwClsContext, out TInterface ppv)
|
||||
where TInterface : class
|
||||
{
|
||||
HRESULT hr = CoCreateInstance(typeof(TClass).GUID, pUnkOuter, dwClsContext, typeof(TInterface).GUID, out object o);
|
||||
ppv = (TInterface)o;
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<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>
|
||||
<None Remove="NativeMethods.json" />
|
||||
<None Remove="NativeMethods.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="NativeMethods.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.49-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
[assembly: InternalsVisibleTo("Snap.Hutao")]
|
||||
|
||||
namespace Snap.Hutao.Win32;
|
||||
|
||||
/// <summary>
|
||||
/// 结构体封送
|
||||
/// </summary>
|
||||
internal static class StructMarshal
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的 <see cref="Windows.Win32.UI.WindowsAndMessaging.WINDOWPLACEMENT"/>
|
||||
/// </summary>
|
||||
/// <returns>新的实例</returns>
|
||||
public static unsafe WINDOWPLACEMENT WINDOWPLACEMENT()
|
||||
{
|
||||
return new() { length = unchecked((uint)sizeof(WINDOWPLACEMENT)) };
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Hutao.Test", "Snap.Hutao.Test\Snap.Hutao.Test.csproj", "{D691BA9F-904C-4229-87A5-E14F2EFF2F64}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Hutao.Win32", "Snap.Hutao.Win32\Snap.Hutao.Win32.csproj", "{0F7ABEB2-5107-4037-B9DC-84D288FB0801}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -67,32 +65,16 @@ Global
|
||||
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|arm64.ActiveCfg = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|arm64.Build.0 = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|arm64.ActiveCfg = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|arm64.Build.0 = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
RESX_Rules = {"EnabledRules":["StringFormat","WhiteSpaceLead","WhiteSpaceTail","PunctuationLead"]}
|
||||
RESX_ShowErrorsInErrorList = False
|
||||
RESX_SortFileContentOnSave = True
|
||||
SolutionGuid = {E4449B1C-0E6A-4D19-955E-1CA491656ABA}
|
||||
RESX_NeutralResourcesLanguage = zh-CN
|
||||
RESX_AutoApplyExistingTranslations = False
|
||||
RESX_NeutralResourcesLanguage = zh-CN
|
||||
SolutionGuid = {E4449B1C-0E6A-4D19-955E-1CA491656ABA}
|
||||
RESX_SortFileContentOnSave = True
|
||||
RESX_ShowErrorsInErrorList = False
|
||||
RESX_Rules = {"EnabledRules":["StringFormat","WhiteSpaceLead","WhiteSpaceTail","PunctuationLead"]}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
x:Key="LargeGridViewItemStyle"
|
||||
BasedOn="{StaticResource DefaultGridViewItemStyle}"
|
||||
TargetType="GridViewItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Margin" Value="0,0,12,12"/>
|
||||
</Style>
|
||||
<Style
|
||||
|
||||
@@ -6,6 +6,7 @@ using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
using Snap.Hutao.Core.Shell;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -36,8 +37,6 @@ public sealed partial class App : Application
|
||||
----------------------------------------------------------------
|
||||
""";
|
||||
|
||||
private const string AppInstanceKey = "main";
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly IActivation activation;
|
||||
private readonly ILogger<App> logger;
|
||||
@@ -50,7 +49,6 @@ public sealed partial class App : Application
|
||||
{
|
||||
// Load app resource
|
||||
InitializeComponent();
|
||||
|
||||
activation = serviceProvider.GetRequiredService<IActivation>();
|
||||
logger = serviceProvider.GetRequiredService<ILogger<App>>();
|
||||
serviceProvider.GetRequiredService<ExceptionRecorder>().Record(this);
|
||||
@@ -64,25 +62,21 @@ public sealed partial class App : Application
|
||||
try
|
||||
{
|
||||
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance firstInstance = AppInstance.FindOrRegisterForKey(AppInstanceKey);
|
||||
|
||||
if (firstInstance.IsCurrent)
|
||||
if (serviceProvider.GetRequiredService<PrivateNamedPipeClient>().TryRedirectActivationTo(activatedEventArgs))
|
||||
{
|
||||
logger.LogInformation(ConsoleBanner);
|
||||
LogDiagnosticInformation();
|
||||
|
||||
// manually invoke
|
||||
activation.NonRedirectToActivate(firstInstance, activatedEventArgs);
|
||||
activation.InitializeWith(firstInstance);
|
||||
|
||||
serviceProvider.GetRequiredService<IJumpListInterop>().ConfigureAsync().SafeForget();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Redirect the activation (and args) to the "main" instance, and exit.
|
||||
firstInstance.RedirectActivationTo(activatedEventArgs);
|
||||
Process.GetCurrentProcess().Kill();
|
||||
Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInformation(ConsoleBanner);
|
||||
LogDiagnosticInformation();
|
||||
|
||||
// manually invoke
|
||||
activation.Activate(HutaoActivationArguments.FromAppActivationArguments(activatedEventArgs));
|
||||
activation.Initialize();
|
||||
|
||||
serviceProvider.GetRequiredService<IJumpListInterop>().ConfigureAsync().SafeForget();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Helper;
|
||||
|
||||
[SuppressMessage("", "SH001")]
|
||||
[DependencyProperty("PaneCornerRadius", typeof(CornerRadius), default, nameof(OnPaneCornerRadiusChanged), IsAttached = true, AttachedType = typeof(NavigationView))]
|
||||
public sealed partial class NavigationViewHelper
|
||||
{
|
||||
private static void OnPaneCornerRadiusChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
NavigationView navigationView = (NavigationView)dp;
|
||||
CornerRadius newValue = (CornerRadius)args.NewValue;
|
||||
|
||||
if (navigationView.IsLoaded)
|
||||
{
|
||||
SetNavigationViewPaneCornerRadius(navigationView, newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
navigationView.Loaded += (s, e) =>
|
||||
{
|
||||
NavigationView loadedNavigationView = (NavigationView)s;
|
||||
SetNavigationViewPaneCornerRadius(loadedNavigationView, newValue);
|
||||
};
|
||||
}
|
||||
|
||||
private static void SetNavigationViewPaneCornerRadius(NavigationView navigationView, CornerRadius value)
|
||||
{
|
||||
if (navigationView.FindDescendant("RootSplitView") is SplitView splitView)
|
||||
{
|
||||
splitView.CornerRadius = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ using Microsoft.UI.Xaml.Controls;
|
||||
namespace Snap.Hutao.Control.Helper;
|
||||
|
||||
[SuppressMessage("", "SH001")]
|
||||
[DependencyProperty("LeftPanelMaxWidth", typeof(double), IsAttached = true, AttachedType = typeof(ScrollViewer))]
|
||||
[DependencyProperty("RightPanel", typeof(UIElement), IsAttached = true, AttachedType = typeof(ScrollViewer))]
|
||||
public sealed partial class ScrollViewerHelper
|
||||
{
|
||||
|
||||
@@ -20,4 +20,4 @@ public sealed partial class SettingsExpanderHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,8 @@ internal struct Rgba32
|
||||
/// <param name="code">RGBA 代码</param>
|
||||
public unsafe Rgba32(uint code)
|
||||
{
|
||||
// RRGGBBAA -> AABBGGRR
|
||||
// uint layout: 0xRRGGBBAA -> AABBGGRR
|
||||
// AABBGGRR -> RRGGBBAA
|
||||
fixed (Rgba32* pSelf = &this)
|
||||
{
|
||||
*(uint*)pSelf = BinaryPrimitives.ReverseEndianness(code);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.System.WinRT;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.System.WinRT;
|
||||
using WinRT;
|
||||
|
||||
namespace Snap.Hutao.Control.Media;
|
||||
|
||||
21
src/Snap.Hutao/Snap.Hutao/Control/Panel/UniformPanel.cs
Normal file
21
src/Snap.Hutao/Snap.Hutao/Control/Panel/UniformPanel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Panel;
|
||||
|
||||
[DependencyProperty("MinItemWidth", typeof(double))]
|
||||
internal sealed partial class UniformPanel : UniformGrid
|
||||
{
|
||||
public UniformPanel()
|
||||
{
|
||||
Columns = 1;
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, Microsoft.UI.Xaml.SizeChangedEventArgs e)
|
||||
{
|
||||
Columns = (int)((e.NewSize.Width + ColumnSpacing) / (MinItemWidth + ColumnSpacing));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Microsoft.UI.Xaml.Media;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Control.Media;
|
||||
using Snap.Hutao.Control.Theme;
|
||||
using System.Diagnostics;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
|
||||
@@ -23,8 +24,11 @@ namespace Snap.Hutao.Control.Text;
|
||||
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
|
||||
internal sealed partial class DescriptionTextBlock : ContentControl
|
||||
{
|
||||
private static readonly int ColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
|
||||
private static readonly int ColorTagLeftLength = "<color=#FFFFFFFF>".Length;
|
||||
private static readonly int RgbaColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
|
||||
private static readonly int RgbaColorTagLeftLength = "<color=#FFFFFFFF>".Length;
|
||||
|
||||
private static readonly int RgbColorTagFullLength = "<color=#FFFFFF></color>".Length;
|
||||
private static readonly int RgbColorTagLeftLength = "<color=#FFFFFF>".Length;
|
||||
|
||||
private static readonly int ItalicTagFullLength = "<i></i>".Length;
|
||||
private static readonly int ItalicTagLeftLength = "<i>".Length;
|
||||
@@ -51,9 +55,16 @@ internal sealed partial class DescriptionTextBlock : ContentControl
|
||||
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
TextBlock textBlock = (TextBlock)((DescriptionTextBlock)d).Content;
|
||||
ReadOnlySpan<char> description = (string)e.NewValue;
|
||||
ReadOnlySpan<char> description = MetadataSpecialNames.Handle((string)e.NewValue);
|
||||
|
||||
UpdateDescription(textBlock, description);
|
||||
try
|
||||
{
|
||||
UpdateDescription(textBlock, description);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ = ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
@@ -81,13 +92,32 @@ internal sealed partial class DescriptionTextBlock : ContentControl
|
||||
// color tag
|
||||
else if (description[i..].StartsWith("<c"))
|
||||
{
|
||||
AppendText(textBlock, description[last..i]);
|
||||
Rgba32 color = new(description.Slice(i + 8, 8).ToString());
|
||||
int length = description[(i + ColorTagLeftLength)..].IndexOf('<');
|
||||
AppendColorText(textBlock, description.Slice(i + ColorTagLeftLength, length), color);
|
||||
switch (description[i..].IndexOf('>'))
|
||||
{
|
||||
case 16: // RgbaColorTag
|
||||
{
|
||||
AppendText(textBlock, description[last..i]);
|
||||
Rgba32 color = new(description.Slice(i + 8, 8).ToString());
|
||||
int length = description[(i + RgbaColorTagLeftLength)..].IndexOf('<');
|
||||
AppendColorText(textBlock, description.Slice(i + RgbaColorTagLeftLength, length), color);
|
||||
|
||||
i += length + ColorTagFullLength;
|
||||
last = i;
|
||||
i += length + RgbaColorTagFullLength;
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: // RgbColorTag
|
||||
{
|
||||
AppendText(textBlock, description[last..i]);
|
||||
Rgba32 color = new(description.Slice(i + 8, 6).ToString());
|
||||
int length = description[(i + RgbColorTagLeftLength)..].IndexOf('<');
|
||||
AppendColorText(textBlock, description.Slice(i + RgbColorTagLeftLength, length), color);
|
||||
|
||||
i += length + RgbColorTagFullLength;
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// italic
|
||||
|
||||
@@ -156,7 +156,7 @@ internal sealed partial class HtmlDescriptionTextBlock : ContentControl
|
||||
text.Inlines.Add(new Run
|
||||
{
|
||||
Text = slice.ToString(),
|
||||
FontWeight = FontWeights.Bold,
|
||||
FontWeight = FontWeights.SemiBold,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Snap.Hutao.Control.Text;
|
||||
|
||||
internal static partial class MetadataSpecialNames
|
||||
{
|
||||
public static string Handle(string input)
|
||||
{
|
||||
if (input.AsSpan()[0] is not '#')
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
StringBuilder resultBuilder = new(input);
|
||||
resultBuilder
|
||||
.Replace("{MATEAVATAR#SEXPRO[INFO_MALE_PRONOUN_BOYD|INFO_FEMALE_PRONOUN_GIRLD]}", SH.ControlTextMetadataSpecialNameMetaAvatarSexProD)
|
||||
.Replace("{PLAYERAVATAR#SEXPRO[INFO_MALE_PRONOUN_HE|INFO_FEMALE_PRONOUN_SHE]}", SH.ControlTextMetadataSpecialNamePlayerAvatarSexPro)
|
||||
.Replace("{REALNAME[ID(1)]}", SH.ControlTextMetadataSpecialNameRealNameId1);
|
||||
|
||||
input = resultBuilder.ToString();
|
||||
|
||||
// {M#.}{F#.}
|
||||
input = MaleFemaleRegex().Replace(input, SH.ControlTextMetadataSpecialNameMaleFemale);
|
||||
|
||||
return input[1..];
|
||||
}
|
||||
|
||||
[GeneratedRegex("\\{M#(.*?)\\}\\{F#(.*?)\\}")]
|
||||
private static partial Regex MaleFemaleRegex();
|
||||
}
|
||||
@@ -24,10 +24,43 @@
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="AcrylicBaseHighBorderCardStyle"
|
||||
BasedOn="{StaticResource BorderCardStyle}"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlBaseHighAcrylicElementBrush}"/>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="AcrylicBorderCardStyle"
|
||||
BasedOn="{StaticResource BorderCardStyle}"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlAcrylicElementMediumHighBrush}"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="GridCardStyle" TargetType="Grid">
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="AcrylicGridCardStyle"
|
||||
BasedOn="{StaticResource GridCardStyle}"
|
||||
TargetType="Grid">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlAcrylicElementMediumHighBrush}"/>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="AcrylicBaseHighGridCardStyle"
|
||||
BasedOn="{StaticResource GridCardStyle}"
|
||||
TargetType="Grid">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource SystemControlBaseHighAcrylicElementBrush}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -2,6 +2,53 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:shch="using:Snap.Hutao.Control.Helper">
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#FDE7E9"
|
||||
TintColor="#FDE7E9"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#FFF4CE"
|
||||
TintColor="#FFF4CE"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#DFF6DD"
|
||||
TintColor="#DFF6DD"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#80F6F6F6"
|
||||
TintColor="#80F6F6F6"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarErrorSeverityBackgroundBrush"
|
||||
FallbackColor="#442726"
|
||||
TintColor="#442726"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarWarningSeverityBackgroundBrush"
|
||||
FallbackColor="#433519"
|
||||
TintColor="#433519"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarSuccessSeverityBackgroundBrush"
|
||||
FallbackColor="#393D1B"
|
||||
TintColor="#393D1B"
|
||||
TintOpacity="0.6"/>
|
||||
<AcrylicBrush
|
||||
x:Key="InfoBarInformationalSeverityBackgroundBrush"
|
||||
FallbackColor="#34424d"
|
||||
TintColor="#34424d"
|
||||
TintOpacity="0.6"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Thickness x:Key="InfoBarIconMargin">19,16,19,16</Thickness>
|
||||
<Thickness x:Key="InfoBarContentRootPadding">0,0,0,0</Thickness>
|
||||
<x:Double x:Key="InfoBarIconFontSize">20</x:Double>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<x:Double x:Key="ContentDialogMinHeight">64</x:Double>
|
||||
<x:Double x:Key="LargeAppBarButtonWidth">100</x:Double>
|
||||
|
||||
<x:Double x:Key="AppBarThemeCompactActualHeight">50</x:Double>
|
||||
|
||||
<!-- ProgressBar -->
|
||||
<x:Double x:Key="LargeBackgroundProgressBarOpacity">0.2</x:Double>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1,5 +1,385 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cw="using:CommunityToolkit.WinUI">
|
||||
<x:Double x:Key="PivotHeaderItemFontSize">16</x:Double>
|
||||
<Thickness x:Key="PivotHeaderItemMargin">16,0,0,0</Thickness>
|
||||
<Thickness x:Key="PivotItemMargin">0</Thickness>
|
||||
|
||||
<Style x:Key="CardPivotStyle" TargetType="Pivot">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource PivotBackground}"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Pivot">
|
||||
<Grid
|
||||
x:Name="RootElement"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
Background="{TemplateBinding Background}">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="BaseContentControlStyle" TargetType="ContentControl">
|
||||
<Setter Property="FontFamily" Value="XamlAutoFontFamily"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ContentControl">
|
||||
<ContentPresenter
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
OpticalMarginAlignment="TrimSideBearings"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TitleContentControlStyle"
|
||||
BasedOn="{StaticResource BaseContentControlStyle}"
|
||||
TargetType="ContentControl">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource PivotTitleFontFamily}"/>
|
||||
<Setter Property="FontWeight" Value="{ThemeResource PivotTitleThemeFontWeight}"/>
|
||||
<Setter Property="FontSize" Value="{ThemeResource PivotTitleFontSize}"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl
|
||||
x:Name="TitleContentControl"
|
||||
Grid.Row="0"
|
||||
Margin="{StaticResource PivotPortraitThemePadding}"
|
||||
Content="{TemplateBinding Title}"
|
||||
ContentTemplate="{TemplateBinding TitleTemplate}"
|
||||
IsTabStop="False"
|
||||
Style="{StaticResource TitleContentControlStyle}"
|
||||
Visibility="Collapsed"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.Resources>
|
||||
<ControlTemplate x:Key="NextTemplate" TargetType="Button">
|
||||
<Border
|
||||
x:Name="Root"
|
||||
Background="{ThemeResource PivotNextButtonBackground}"
|
||||
BorderBrush="{ThemeResource PivotNextButtonBorderBrush}"
|
||||
BorderThickness="{ThemeResource PivotNavButtonBorderThemeThickness}">
|
||||
<FontIcon
|
||||
x:Name="Arrow"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource PivotNextButtonForeground}"
|
||||
Glyph=""
|
||||
MirroredWhenRightToLeft="True"
|
||||
UseLayoutRounding="False"/>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonBackgroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonBorderBrushPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonForegroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonBackgroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonBorderBrushPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotNextButtonForegroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="PreviousTemplate" TargetType="Button">
|
||||
<Border
|
||||
x:Name="Root"
|
||||
Background="{ThemeResource PivotPreviousButtonBackground}"
|
||||
BorderBrush="{ThemeResource PivotPreviousButtonBorderBrush}"
|
||||
BorderThickness="{ThemeResource PivotNavButtonBorderThemeThickness}">
|
||||
<FontIcon
|
||||
x:Name="Arrow"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource PivotPreviousButtonForeground}"
|
||||
Glyph=""
|
||||
MirroredWhenRightToLeft="True"
|
||||
UseLayoutRounding="False"/>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonBackgroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonBorderBrushPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonForegroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonBackgroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonBorderBrushPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPreviousButtonForegroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Grid.Resources>
|
||||
<ScrollViewer
|
||||
x:Name="ScrollViewer"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BringIntoViewOnFocusChange="False"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
HorizontalSnapPointsAlignment="Center"
|
||||
HorizontalSnapPointsType="MandatorySingle"
|
||||
Template="{StaticResource ScrollViewerScrollBarlessTemplate}"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
VerticalScrollMode="Disabled"
|
||||
VerticalSnapPointsType="None"
|
||||
ZoomMode="Disabled">
|
||||
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch">
|
||||
<Grid x:Name="PivotLayoutElement">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.RenderTransform>
|
||||
<CompositeTransform x:Name="PivotLayoutElementTranslateTransform"/>
|
||||
</Grid.RenderTransform>
|
||||
|
||||
|
||||
|
||||
<ItemsPresenter x:Name="PivotItemPresenter" Grid.Row="1">
|
||||
<ItemsPresenter.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TranslateTransform x:Name="ItemsPresenterTranslateTransform"/>
|
||||
<CompositeTransform x:Name="ItemsPresenterCompositeTransform"/>
|
||||
</TransformGroup>
|
||||
</ItemsPresenter.RenderTransform>
|
||||
</ItemsPresenter>
|
||||
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Margin="16,16,16,0"
|
||||
cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Grid Style="{ThemeResource AcrylicBaseHighGridCardStyle}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="LeftHeaderPresenter"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{TemplateBinding LeftHeader}"
|
||||
ContentTemplate="{TemplateBinding LeftHeaderTemplate}"/>
|
||||
<ContentControl
|
||||
x:Name="HeaderClipper"
|
||||
Grid.Column="1"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
UseSystemFocusVisuals="{StaticResource UseSystemFocusVisuals}">
|
||||
<ContentControl.Clip>
|
||||
<RectangleGeometry x:Name="HeaderClipperGeometry"/>
|
||||
</ContentControl.Clip>
|
||||
<Grid>
|
||||
<Grid.RenderTransform>
|
||||
<CompositeTransform x:Name="HeaderOffsetTranslateTransform"/>
|
||||
</Grid.RenderTransform>
|
||||
<PivotHeaderPanel x:Name="StaticHeader" Visibility="Collapsed">
|
||||
<PivotHeaderPanel.RenderTransform>
|
||||
<CompositeTransform x:Name="StaticHeaderTranslateTransform"/>
|
||||
</PivotHeaderPanel.RenderTransform>
|
||||
</PivotHeaderPanel>
|
||||
<PivotHeaderPanel x:Name="Header">
|
||||
<PivotHeaderPanel.RenderTransform>
|
||||
<CompositeTransform x:Name="HeaderTranslateTransform"/>
|
||||
</PivotHeaderPanel.RenderTransform>
|
||||
</PivotHeaderPanel>
|
||||
<Rectangle
|
||||
x:Name="FocusFollower"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Control.IsTemplateFocusTarget="True"
|
||||
Fill="Transparent"
|
||||
IsHitTestVisible="False"/>
|
||||
</Grid>
|
||||
</ContentControl>
|
||||
<Button
|
||||
x:Name="PreviousButton"
|
||||
Grid.Column="1"
|
||||
Width="20"
|
||||
Height="36"
|
||||
Margin="{ThemeResource PivotNavButtonMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
IsEnabled="False"
|
||||
IsTabStop="False"
|
||||
Opacity="0"
|
||||
Template="{StaticResource PreviousTemplate}"
|
||||
UseSystemFocusVisuals="False"/>
|
||||
<Button
|
||||
x:Name="NextButton"
|
||||
Grid.Column="1"
|
||||
Width="20"
|
||||
Height="36"
|
||||
Margin="{ThemeResource PivotNavButtonMargin}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
IsEnabled="False"
|
||||
IsTabStop="False"
|
||||
Opacity="0"
|
||||
Template="{StaticResource NextTemplate}"
|
||||
UseSystemFocusVisuals="False"/>
|
||||
<ContentPresenter
|
||||
x:Name="RightHeaderPresenter"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{TemplateBinding RightHeader}"
|
||||
ContentTemplate="{TemplateBinding RightHeaderTemplate}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
</PivotPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="Orientation">
|
||||
<VisualState x:Name="Portrait">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TitleContentControl" Storyboard.TargetProperty="Margin">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPortraitThemePadding}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Landscape">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TitleContentControl" Storyboard.TargetProperty="Margin">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotLandscapeThemePadding}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="NavigationButtonsVisibility">
|
||||
<VisualState x:Name="NavigationButtonsHidden"/>
|
||||
<VisualState x:Name="NavigationButtonsVisible">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="NextButton" Storyboard.TargetProperty="Opacity">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="NextButton" Storyboard.TargetProperty="IsEnabled">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousButton" Storyboard.TargetProperty="Opacity">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousButton" Storyboard.TargetProperty="IsEnabled">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PreviousButtonVisible">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousButton" Storyboard.TargetProperty="Opacity">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousButton" Storyboard.TargetProperty="IsEnabled">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="NextButtonVisible">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="NextButton" Storyboard.TargetProperty="Opacity">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="NextButton" Storyboard.TargetProperty="IsEnabled">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="HeaderStates">
|
||||
<VisualState x:Name="HeaderDynamic"/>
|
||||
<VisualState x:Name="HeaderStatic">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Header" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="StaticHeader" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -42,7 +42,7 @@
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{TemplateBinding Padding}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MaxWidth="{Binding Path=(shch:ScrollViewerHelper.LeftPanelMaxWidth), RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollContentPresenter x:Name="ScrollContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"/>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls">
|
||||
<!-- Settings -->
|
||||
<x:Double x:Key="SettingsCardSpacing">3</x:Double>
|
||||
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<x:String x:Key="DocumentLink_Home">https://hut.ao</x:String>
|
||||
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html</x:String>
|
||||
<x:String x:Key="DocumentLink_Translate">https://translate.hut.ao</x:String>
|
||||
<x:String x:Key="DocumentLink_Loopback">https://hut.ao/zh/advanced/FAQ.html#%E5%A6%82%E4%BD%95%E9%80%9A%E8%BF%87%E7%BD%91%E7%BB%9C%E4%BB%A3%E7%90%86%E4%BD%BF%E7%94%A8%E8%83%A1%E6%A1%83%E5%B7%A5%E5%85%B7%E7%AE%B1</x:String>
|
||||
|
||||
<!-- Other -->
|
||||
<x:String x:Key="HolographicHat_GetToken_Release">https://github.com/HolographicHat/GetToken/releases/latest</x:String>
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Snap.Hutao.Core.IO.Http.DynamicProxy;
|
||||
using Microsoft.Extensions.Http;
|
||||
using Snap.Hutao.Core.IO.Http.Proxy;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Service;
|
||||
using System.Globalization;
|
||||
@@ -33,7 +34,7 @@ internal static class DependencyInjection
|
||||
.AddJsonOptions()
|
||||
.AddDatabase()
|
||||
.AddInjections()
|
||||
.AddHttpClients()
|
||||
.AddAllHttpClients()
|
||||
|
||||
// Discrete services
|
||||
.AddSingleton<IMessenger, WeakReferenceMessenger>()
|
||||
@@ -43,7 +44,6 @@ internal static class DependencyInjection
|
||||
|
||||
serviceProvider.InitializeConsoleWindow();
|
||||
serviceProvider.InitializeCulture();
|
||||
serviceProvider.InitializedDynamicHttpProxy();
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
@@ -70,9 +70,4 @@ internal static class DependencyInjection
|
||||
{
|
||||
_ = serviceProvider.GetRequiredService<ConsoleWindowLifeTime>();
|
||||
}
|
||||
|
||||
private static void InitializedDynamicHttpProxy(this IServiceProvider serviceProvider)
|
||||
{
|
||||
HttpClient.DefaultProxy = serviceProvider.GetRequiredService<DynamicHttpProxy>();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.IO.Http.Proxy;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -14,12 +15,26 @@ internal static partial class IocHttpClientConfiguration
|
||||
{
|
||||
private const string ApplicationJson = "application/json";
|
||||
|
||||
/// <summary>
|
||||
/// 添加 <see cref="HttpClient"/>
|
||||
/// 此方法将会自动生成
|
||||
/// </summary>
|
||||
/// <param name="services">集合</param>
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddAllHttpClients(this IServiceCollection services)
|
||||
{
|
||||
services
|
||||
.ConfigureHttpClientDefaults(clientBuilder =>
|
||||
{
|
||||
clientBuilder
|
||||
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler())
|
||||
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
|
||||
{
|
||||
HttpClientHandler clientHandler = (HttpClientHandler)handler;
|
||||
clientHandler.UseProxy = true;
|
||||
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
|
||||
});
|
||||
})
|
||||
.AddHttpClients();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static partial IServiceCollection AddHttpClients(this IServiceCollection services);
|
||||
|
||||
/// <summary>
|
||||
@@ -89,6 +104,7 @@ internal static partial class IocHttpClientConfiguration
|
||||
/// HoYoLAB web
|
||||
/// </summary>
|
||||
/// <param name="client">配置后的客户端</param>
|
||||
[SuppressMessage("", "IDE0051")]
|
||||
private static void XRpc4Configuration(HttpClient client)
|
||||
{
|
||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||
|
||||
@@ -11,10 +11,18 @@ internal sealed class HutaoException : Exception
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public HutaoException(string message, Exception? innerException)
|
||||
private HutaoException(string message, Exception? innerException)
|
||||
: base($"{message}\n{innerException?.Message}", innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public HutaoExceptionKind Kind { get; private set; }
|
||||
|
||||
public static void ThrowIf(bool condition, HutaoExceptionKind kind, string message, Exception? innerException = default)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
throw new HutaoException(kind, message, innerException);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Game.Package;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.ExceptionService;
|
||||
@@ -35,6 +36,22 @@ internal static class ThrowHelper
|
||||
throw new GameFileOperationException(message, inner);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static InvalidDataException InvalidData(string message, Exception? inner = default)
|
||||
{
|
||||
throw new InvalidDataException(message, inner);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void InvalidDataIf([DoesNotReturnIf(true)] bool condition, string message, Exception? inner = default)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
throw new InvalidDataException(message, inner);
|
||||
}
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static InvalidOperationException InvalidOperation(string message, Exception? inner = default)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.NetworkManagement.WindowsFirewall;
|
||||
using Snap.Hutao.Win32.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Snap.Hutao.Win32.AdvApi32;
|
||||
using static Snap.Hutao.Win32.ApiMsWinNetIsolation;
|
||||
using static Snap.Hutao.Win32.Macros;
|
||||
|
||||
namespace Snap.Hutao.Core.IO.Http.Loopback;
|
||||
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed unsafe class LoopbackManager : ObservableObject
|
||||
{
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private readonly string hutaoContainerStringSID = default!;
|
||||
private bool isLoopbackEnabled;
|
||||
|
||||
public LoopbackManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
|
||||
INET_FIREWALL_APP_CONTAINER* pContainers = default;
|
||||
try
|
||||
{
|
||||
WIN32_ERROR error = NetworkIsolationEnumAppContainers(NETISO_FLAG.NETISO_FLAG_MAX, out uint acCount, out pContainers);
|
||||
Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(error));
|
||||
for (uint i = 0; i < acCount; i++)
|
||||
{
|
||||
INET_FIREWALL_APP_CONTAINER* pContainer = pContainers + i;
|
||||
ReadOnlySpan<char> appContainerName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(pContainer->appContainerName);
|
||||
if (appContainerName.Equals(runtimeOptions.FamilyName, StringComparison.Ordinal))
|
||||
{
|
||||
ConvertSidToStringSidW(pContainer->appContainerSid, out PWSTR stringSid);
|
||||
hutaoContainerStringSID = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(stringSid).ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// This function returns 1 rather than 0 specfied in the document.
|
||||
_ = NetworkIsolationFreeAppContainers(pContainers);
|
||||
}
|
||||
|
||||
WIN32_ERROR error2 = NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids);
|
||||
Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(error2));
|
||||
for (uint i = 0; i < accCount; i++)
|
||||
{
|
||||
ConvertSidToStringSidW((pSids + i)->Sid, out PWSTR stringSid);
|
||||
ReadOnlySpan<char> stringSidSpan = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(stringSid);
|
||||
if (stringSidSpan.Equals(hutaoContainerStringSID, StringComparison.Ordinal))
|
||||
{
|
||||
IsLoopbackEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoopbackEnabled { get => isLoopbackEnabled; private set => SetProperty(ref isLoopbackEnabled, value); }
|
||||
|
||||
public void EnableLoopback()
|
||||
{
|
||||
NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids);
|
||||
List<SID_AND_ATTRIBUTES> sids = new((int)(accCount + 1));
|
||||
for (uint i = 0; i < accCount; i++)
|
||||
{
|
||||
sids.Add(*(pSids + i));
|
||||
}
|
||||
|
||||
ConvertStringSidToSidW(hutaoContainerStringSID, out PSID pSid);
|
||||
SID_AND_ATTRIBUTES sidAndAttributes = default;
|
||||
sidAndAttributes.Sid = pSid;
|
||||
sids.Add(sidAndAttributes);
|
||||
IsLoopbackEnabled = NetworkIsolationSetAppContainerConfig(CollectionsMarshal.AsSpan(sids)) is WIN32_ERROR.ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,46 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// 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;
|
||||
namespace Snap.Hutao.Core.IO.Http.Proxy;
|
||||
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable
|
||||
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 static readonly Lazy<MethodInfo> LazyConstructSystemProxyMethod = new(GetConstructSystemProxyMethod);
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly RegistryWatcher watcher;
|
||||
|
||||
private IWebProxy innerProxy = default!;
|
||||
|
||||
static DynamicHttpProxy()
|
||||
public DynamicHttpProxy(IServiceProvider serviceProvider)
|
||||
{
|
||||
Type? systemProxyInfoType = typeof(System.Net.Http.SocketsHttpHandler).Assembly.GetType("System.Net.Http.SystemProxyInfo");
|
||||
ArgumentNullException.ThrowIfNull(systemProxyInfoType);
|
||||
this.serviceProvider = serviceProvider;
|
||||
UpdateInnerProxy();
|
||||
|
||||
MethodInfo? constructSystemProxyMethod = systemProxyInfoType.GetMethod("ConstructSystemProxy", BindingFlags.Static | BindingFlags.Public);
|
||||
ArgumentNullException.ThrowIfNull(constructSystemProxyMethod);
|
||||
ConstructSystemProxyMethod = constructSystemProxyMethod;
|
||||
}
|
||||
|
||||
public DynamicHttpProxy()
|
||||
{
|
||||
UpdateProxy();
|
||||
|
||||
watcher = new(ProxySettingPath, UpdateProxy);
|
||||
watcher = new(ProxySettingPath, OnSystemProxySettingsChanged);
|
||||
watcher.Start();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICredentials? Credentials
|
||||
public string CurrentProxyUri
|
||||
{
|
||||
get => InnerProxy.Credentials;
|
||||
set => InnerProxy.Credentials = value;
|
||||
get
|
||||
{
|
||||
Uri? proxyUri = GetProxy("https://hut.ao".ToUri());
|
||||
return proxyUri is null
|
||||
? SH.ViewPageFeedbackCurrentProxyNoProxyDescription
|
||||
: proxyUri.AbsoluteUri;
|
||||
}
|
||||
}
|
||||
|
||||
private IWebProxy InnerProxy
|
||||
public IWebProxy InnerProxy
|
||||
{
|
||||
get => innerProxy;
|
||||
|
||||
@@ -60,13 +57,10 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(innerProxy))]
|
||||
public void UpdateProxy()
|
||||
public ICredentials? Credentials
|
||||
{
|
||||
IWebProxy? proxy = ConstructSystemProxyMethod.Invoke(default, default) as IWebProxy;
|
||||
ArgumentNullException.ThrowIfNull(proxy);
|
||||
|
||||
InnerProxy = proxy;
|
||||
get => InnerProxy.Credentials;
|
||||
set => InnerProxy.Credentials = value;
|
||||
}
|
||||
|
||||
public Uri? GetProxy(Uri destination)
|
||||
@@ -84,4 +78,33 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable
|
||||
(innerProxy as IDisposable)?.Dispose();
|
||||
watcher.Dispose();
|
||||
}
|
||||
|
||||
public void OnSystemProxySettingsChanged()
|
||||
{
|
||||
UpdateInnerProxy();
|
||||
|
||||
// TaskContext can't be injected directly since there are some recursive dependencies.
|
||||
ITaskContext taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
taskContext.BeginInvokeOnMainThread(() => OnPropertyChanged(nameof(CurrentProxyUri)));
|
||||
}
|
||||
|
||||
private static MethodInfo GetConstructSystemProxyMethod()
|
||||
{
|
||||
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);
|
||||
|
||||
return constructSystemProxyMethod;
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(innerProxy))]
|
||||
private void UpdateInnerProxy()
|
||||
{
|
||||
IWebProxy? proxy = LazyConstructSystemProxyMethod.Value.Invoke(default, default) as IWebProxy;
|
||||
ArgumentNullException.ThrowIfNull(proxy);
|
||||
|
||||
InnerProxy = proxy;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ internal sealed class HttpShardCopyWorker<TStatus> : IDisposable
|
||||
private readonly long contentLength;
|
||||
private readonly int bufferSize;
|
||||
private readonly SafeFileHandle destFileHandle;
|
||||
private readonly int maxDegreeOfParallelism;
|
||||
private readonly List<Shard> shards;
|
||||
|
||||
private HttpShardCopyWorker(HttpShardCopyWorkerOptions<TStatus> options)
|
||||
@@ -28,6 +29,7 @@ internal sealed class HttpShardCopyWorker<TStatus> : IDisposable
|
||||
contentLength = options.ContentLength;
|
||||
bufferSize = options.BufferSize;
|
||||
destFileHandle = options.GetFileHandle();
|
||||
maxDegreeOfParallelism = options.MaxDegreeOfParallelism;
|
||||
shards = CalculateShards(contentLength);
|
||||
|
||||
static List<Shard> CalculateShards(long contentLength)
|
||||
@@ -56,7 +58,11 @@ internal sealed class HttpShardCopyWorker<TStatus> : IDisposable
|
||||
public Task CopyAsync(IProgress<TStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
ShardProgress shardProgress = new(progress, statusFactory, contentLength);
|
||||
return Parallel.ForEachAsync(shards, token, (shard, token) => CopyShardAsync(shard, shardProgress, token));
|
||||
ParallelOptions parallelOptions = new()
|
||||
{
|
||||
MaxDegreeOfParallelism = maxDegreeOfParallelism,
|
||||
};
|
||||
return Parallel.ForEachAsync(shards, parallelOptions, (shard, token) => CopyShardAsync(shard, shardProgress, token));
|
||||
|
||||
async ValueTask CopyShardAsync(Shard shard, IProgress<ShardStatus> progress, CancellationToken token)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,8 @@ internal sealed class HttpShardCopyWorkerOptions<TStatus>
|
||||
|
||||
public int BufferSize { get; set; } = 80 * 1024;
|
||||
|
||||
public int MaxDegreeOfParallelism { get; set; } = Environment.ProcessorCount;
|
||||
|
||||
public SafeFileHandle GetFileHandle()
|
||||
{
|
||||
return File.OpenHandle(DestinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, FileOptions.RandomAccess | FileOptions.Asynchronous, ContentLength);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service.DailyNote;
|
||||
using Snap.Hutao.Service.Discord;
|
||||
@@ -24,24 +24,9 @@ namespace Snap.Hutao.Core.LifeCycle;
|
||||
[SuppressMessage("", "CA1001")]
|
||||
internal sealed partial class Activation : IActivation
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作
|
||||
/// </summary>
|
||||
public const string Action = nameof(Action);
|
||||
|
||||
/// <summary>
|
||||
/// Uid
|
||||
/// </summary>
|
||||
public const string Uid = nameof(Uid);
|
||||
|
||||
/// <summary>
|
||||
/// 启动游戏启动参数
|
||||
/// </summary>
|
||||
public const string LaunchGame = nameof(LaunchGame);
|
||||
|
||||
/// <summary>
|
||||
/// 从剪贴板导入成就
|
||||
/// </summary>
|
||||
public const string ImportUIAFFromClipboard = nameof(ImportUIAFFromClipboard);
|
||||
|
||||
private const string CategoryAchievement = "ACHIEVEMENT";
|
||||
@@ -55,29 +40,20 @@ internal sealed partial class Activation : IActivation
|
||||
private readonly SemaphoreSlim activateSemaphore = new(1);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Activate(object? sender, AppActivationArguments args)
|
||||
public void Activate(HutaoActivationArguments args)
|
||||
{
|
||||
_ = sender;
|
||||
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
||||
if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
||||
{
|
||||
HandleActivationAsync(args, true).SafeForget();
|
||||
return;
|
||||
}
|
||||
|
||||
HandleActivationAsync(args).SafeForget();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void NonRedirectToActivate(object? sender, AppActivationArguments args)
|
||||
public void Initialize()
|
||||
{
|
||||
_ = sender;
|
||||
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
||||
{
|
||||
HandleActivationAsync(args, false).SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void InitializeWith(AppInstance appInstance)
|
||||
{
|
||||
appInstance.Activated += Activate;
|
||||
serviceProvider.GetRequiredService<PrivateNamedPipeServer>().RunAsync().SafeForget();
|
||||
ToastNotificationManagerCompat.OnActivated += NotificationActivate;
|
||||
}
|
||||
|
||||
@@ -95,44 +71,40 @@ internal sealed partial class Activation : IActivation
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleActivationAsync(AppActivationArguments args, bool isRedirected)
|
||||
private async ValueTask HandleActivationAsync(HutaoActivationArguments args)
|
||||
{
|
||||
if (activateSemaphore.CurrentCount > 0)
|
||||
{
|
||||
using (await activateSemaphore.EnterAsync().ConfigureAwait(false))
|
||||
{
|
||||
await HandleActivationCoreAsync(args, isRedirected).ConfigureAwait(false);
|
||||
await HandleActivationCoreAsync(args).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleActivationCoreAsync(AppActivationArguments args, bool isRedirected)
|
||||
private async ValueTask HandleActivationCoreAsync(HutaoActivationArguments args)
|
||||
{
|
||||
if (args.Kind == ExtendedActivationKind.Protocol)
|
||||
if (args.Kind is HutaoActivationKind.Protocol)
|
||||
{
|
||||
if (args.TryGetProtocolActivatedUri(out Uri? uri))
|
||||
{
|
||||
await HandleUrlActivationAsync(uri, isRedirected).ConfigureAwait(false);
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(args.ProtocolActivatedUri);
|
||||
await HandleUrlActivationAsync(args.ProtocolActivatedUri, args.IsRedirectTo).ConfigureAwait(false);
|
||||
}
|
||||
else if (args.Kind == ExtendedActivationKind.Launch)
|
||||
else if (args.Kind is HutaoActivationKind.Launch)
|
||||
{
|
||||
if (args.TryGetLaunchActivatedArgument(out string? arguments))
|
||||
ArgumentNullException.ThrowIfNull(args.LaunchActivatedArguments);
|
||||
switch (args.LaunchActivatedArguments)
|
||||
{
|
||||
switch (arguments)
|
||||
{
|
||||
case LaunchGame:
|
||||
{
|
||||
await HandleLaunchGameActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
case LaunchGame:
|
||||
{
|
||||
await HandleLaunchGameActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
await HandleNormalLaunchActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
await HandleNormalLaunchActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +166,7 @@ internal sealed partial class Activation : IActivation
|
||||
.SafeForget();
|
||||
}
|
||||
|
||||
private async ValueTask HandleUrlActivationAsync(Uri uri, bool isRedirected)
|
||||
private async ValueTask HandleUrlActivationAsync(Uri uri, bool isRedirectTo)
|
||||
{
|
||||
UriBuilder builder = new(uri);
|
||||
|
||||
@@ -207,13 +179,13 @@ internal sealed partial class Activation : IActivation
|
||||
case CategoryAchievement:
|
||||
{
|
||||
await WaitMainWindowAsync().ConfigureAwait(false);
|
||||
await HandleAchievementActionAsync(action, parameter, isRedirected).ConfigureAwait(false);
|
||||
await HandleAchievementActionAsync(action, parameter, isRedirectTo).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case CategoryDailyNote:
|
||||
{
|
||||
await HandleDailyNoteActionAsync(action, parameter, isRedirected).ConfigureAwait(false);
|
||||
await HandleDailyNoteActionAsync(action, parameter, isRedirectTo).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -225,10 +197,10 @@ internal sealed partial class Activation : IActivation
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleAchievementActionAsync(string action, string parameter, bool isRedirected)
|
||||
private async ValueTask HandleAchievementActionAsync(string action, string parameter, bool isRedirectTo)
|
||||
{
|
||||
_ = parameter;
|
||||
_ = isRedirected;
|
||||
_ = isRedirectTo;
|
||||
switch (action)
|
||||
{
|
||||
case UrlActionImport:
|
||||
@@ -245,7 +217,7 @@ internal sealed partial class Activation : IActivation
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleDailyNoteActionAsync(string action, string parameter, bool isRedirected)
|
||||
private async ValueTask HandleDailyNoteActionAsync(string action, string parameter, bool isRedirectTo)
|
||||
{
|
||||
_ = parameter;
|
||||
switch (action)
|
||||
@@ -264,7 +236,7 @@ internal sealed partial class Activation : IActivation
|
||||
}
|
||||
|
||||
// Check if it's redirected.
|
||||
if (!isRedirected)
|
||||
if (!isRedirectTo)
|
||||
{
|
||||
// It's a direct open process, should exit immediately.
|
||||
Process.GetCurrentProcess().Kill();
|
||||
|
||||
@@ -36,7 +36,7 @@ internal static class AppActivationArgumentsExtensions
|
||||
/// <param name="activatedEventArgs">应用程序激活参数</param>
|
||||
/// <param name="arguments">参数</param>
|
||||
/// <returns>是否存在参数</returns>
|
||||
public static bool TryGetLaunchActivatedArgument(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out string? arguments)
|
||||
public static bool TryGetLaunchActivatedArguments(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out string? arguments)
|
||||
{
|
||||
arguments = null;
|
||||
if (activatedEventArgs.Data is not ILaunchActivatedEventArgs launchArgs)
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Security;
|
||||
using Windows.Win32.System.Com;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
using static Snap.Hutao.Win32.Kernel32;
|
||||
using static Snap.Hutao.Win32.Ole32;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
|
||||
@@ -18,7 +19,7 @@ internal static class AppInstanceExtension
|
||||
private static readonly WaitCallback RunActionWaitCallback = RunAction;
|
||||
|
||||
// Hold the reference here to prevent memory corruption.
|
||||
private static HANDLE redirectEventHandle = HANDLE.Null;
|
||||
private static HANDLE redirectEventHandle;
|
||||
|
||||
/// <summary>
|
||||
/// 同步非阻塞重定向
|
||||
@@ -27,19 +28,24 @@ internal static class AppInstanceExtension
|
||||
/// <param name="args">参数</param>
|
||||
public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
||||
{
|
||||
redirectEventHandle = CreateEvent(default(SECURITY_ATTRIBUTES*), true, false, null);
|
||||
|
||||
// use ThreadPool.UnsafeQueueUserWorkItem to cancel stacktrace
|
||||
// like ExecutionContext.SuppressFlow
|
||||
ThreadPool.UnsafeQueueUserWorkItem(RunActionWaitCallback, () =>
|
||||
try
|
||||
{
|
||||
appInstance.RedirectActivationToAsync(args).AsTask().Wait();
|
||||
SetEvent(redirectEventHandle);
|
||||
});
|
||||
redirectEventHandle = CreateEventW(default, true, false, default);
|
||||
|
||||
ReadOnlySpan<HANDLE> handles = new(ref redirectEventHandle);
|
||||
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
||||
CloseHandle(redirectEventHandle);
|
||||
// use ThreadPool.UnsafeQueueUserWorkItem to cancel stacktrace
|
||||
// like ExecutionContext.SuppressFlow
|
||||
ThreadPool.UnsafeQueueUserWorkItem(RunActionWaitCallback, () =>
|
||||
{
|
||||
appInstance.RedirectActivationToAsync(args).AsTask().Wait();
|
||||
SetEvent(redirectEventHandle);
|
||||
});
|
||||
|
||||
CoWaitForMultipleObjects(CWMO_FLAGS.CWMO_DEFAULT, INFINITE, [redirectEventHandle], out uint _);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseHandle(redirectEventHandle);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SH007")]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Windows.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
@@ -19,6 +19,6 @@ internal static class CurrentWindowReferenceExtension
|
||||
{
|
||||
return reference.Window is IWindowOptionsSource optionsSource
|
||||
? optionsSource.WindowOptions.Hwnd
|
||||
: (HWND)WindowNative.GetWindowHandle(reference.Window);
|
||||
: WindowNative.GetWindowHandle(reference.Window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
|
||||
internal sealed class HutaoActivationArguments
|
||||
{
|
||||
public bool IsRedirectTo { get; set; }
|
||||
|
||||
public HutaoActivationKind Kind { get; set; }
|
||||
|
||||
public Uri? ProtocolActivatedUri { get; set; }
|
||||
|
||||
public string? LaunchActivatedArguments { get; set; }
|
||||
|
||||
public static HutaoActivationArguments FromAppActivationArguments(AppActivationArguments args, bool isRedirected = false)
|
||||
{
|
||||
HutaoActivationArguments result = new()
|
||||
{
|
||||
IsRedirectTo = isRedirected,
|
||||
};
|
||||
|
||||
switch (args.Kind)
|
||||
{
|
||||
case ExtendedActivationKind.Launch:
|
||||
{
|
||||
result.Kind = HutaoActivationKind.Launch;
|
||||
if (args.TryGetLaunchActivatedArguments(out string? arguments))
|
||||
{
|
||||
result.LaunchActivatedArguments = arguments;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ExtendedActivationKind.Protocol:
|
||||
{
|
||||
result.Kind = HutaoActivationKind.Protocol;
|
||||
if (args.TryGetProtocolActivatedUri(out Uri? uri))
|
||||
{
|
||||
result.ProtocolActivatedUri = uri;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
|
||||
internal enum HutaoActivationKind
|
||||
{
|
||||
None,
|
||||
Launch,
|
||||
Protocol,
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
|
||||
/// <summary>
|
||||
@@ -10,24 +8,7 @@ namespace Snap.Hutao.Core.LifeCycle;
|
||||
/// </summary>
|
||||
internal interface IActivation
|
||||
{
|
||||
/// <summary>
|
||||
/// 响应激活事件
|
||||
/// 激活事件一般不会在UI线程上触发
|
||||
/// </summary>
|
||||
/// <param name="sender">发送方</param>
|
||||
/// <param name="args">激活参数</param>
|
||||
void Activate(object? sender, AppActivationArguments args);
|
||||
void Activate(HutaoActivationArguments args);
|
||||
|
||||
/// <summary>
|
||||
/// 使用当前 App 实例初始化激活
|
||||
/// </summary>
|
||||
/// <param name="appInstance">App 实例</param>
|
||||
void InitializeWith(AppInstance appInstance);
|
||||
|
||||
/// <summary>
|
||||
/// 无转发触发激活事件
|
||||
/// </summary>
|
||||
/// <param name="sender">发送方</param>
|
||||
/// <param name="args">激活参数</param>
|
||||
void NonRedirectToActivate(object? sender, AppActivationArguments args);
|
||||
void Initialize();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
internal static class NamedPipeClientStreamExtension
|
||||
{
|
||||
public static bool TryConnectOnce(this NamedPipeClientStream clientStream)
|
||||
{
|
||||
try
|
||||
{
|
||||
clientStream.Connect(TimeSpan.Zero);
|
||||
return true;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
internal enum PipePacketCommand : byte
|
||||
{
|
||||
None = 0,
|
||||
|
||||
RedirectActivation = 10,
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
internal enum PipePacketContentType : byte
|
||||
{
|
||||
None = 0,
|
||||
Json = 1,
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct PipePacketHeader
|
||||
{
|
||||
public byte Version;
|
||||
public PipePacketType Type;
|
||||
public PipePacketCommand Command;
|
||||
public PipePacketContentType ContentType;
|
||||
public int ContentLength;
|
||||
public ulong Checksum;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
internal enum PipePacketType : byte
|
||||
{
|
||||
None = 0,
|
||||
Request = 1,
|
||||
Response = 2,
|
||||
Termination = 3,
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using System.IO.Hashing;
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class PrivateNamedPipeClient : IDisposable
|
||||
{
|
||||
private readonly NamedPipeClientStream clientStream = new(".", "Snap.Hutao.PrivateNamedPipe", PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
|
||||
|
||||
public unsafe bool TryRedirectActivationTo(AppActivationArguments args)
|
||||
{
|
||||
if (clientStream.TryConnectOnce())
|
||||
{
|
||||
{
|
||||
PipePacketHeader redirectActivationPacket = default;
|
||||
redirectActivationPacket.Version = 1;
|
||||
redirectActivationPacket.Type = PipePacketType.Request;
|
||||
redirectActivationPacket.Command = PipePacketCommand.RedirectActivation;
|
||||
redirectActivationPacket.ContentType = PipePacketContentType.Json;
|
||||
|
||||
HutaoActivationArguments hutaoArgs = HutaoActivationArguments.FromAppActivationArguments(args, isRedirected: true);
|
||||
byte[] jsonBytes = JsonSerializer.SerializeToUtf8Bytes(hutaoArgs);
|
||||
|
||||
redirectActivationPacket.ContentLength = jsonBytes.Length;
|
||||
redirectActivationPacket.Checksum = XxHash64.HashToUInt64(jsonBytes);
|
||||
|
||||
clientStream.Write(new(&redirectActivationPacket, sizeof(PipePacketHeader)));
|
||||
clientStream.Write(jsonBytes);
|
||||
}
|
||||
|
||||
{
|
||||
PipePacketHeader terminationPacket = default;
|
||||
terminationPacket.Version = 1;
|
||||
terminationPacket.Type = PipePacketType.Termination;
|
||||
|
||||
clientStream.Write(new(&terminationPacket, sizeof(PipePacketHeader)));
|
||||
}
|
||||
|
||||
clientStream.Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
clientStream.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
[Injection(InjectAs.Singleton)]
|
||||
[ConstructorGenerated]
|
||||
internal sealed partial class PrivateNamedPipeMessageDispatcher
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public void RedirectActivation(HutaoActivationArguments? args)
|
||||
{
|
||||
if (args is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
serviceProvider.GetRequiredService<IActivation>().Activate(args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using System.IO.Hashing;
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle.InterProcess;
|
||||
|
||||
[Injection(InjectAs.Singleton)]
|
||||
[ConstructorGenerated]
|
||||
internal sealed partial class PrivateNamedPipeServer : IDisposable
|
||||
{
|
||||
private readonly PrivateNamedPipeMessageDispatcher messageDispatcher;
|
||||
|
||||
private readonly NamedPipeServerStream serverStream = new("Snap.Hutao.PrivateNamedPipe", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
|
||||
private readonly CancellationTokenSource serverTokenSource = new();
|
||||
private readonly SemaphoreSlim serverSemaphore = new(1);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
serverTokenSource.Cancel();
|
||||
serverSemaphore.Wait();
|
||||
serverSemaphore.Dispose();
|
||||
serverTokenSource.Dispose();
|
||||
|
||||
serverStream.Dispose();
|
||||
}
|
||||
|
||||
public async ValueTask RunAsync()
|
||||
{
|
||||
using (await serverSemaphore.EnterAsync(serverTokenSource.Token).ConfigureAwait(false))
|
||||
{
|
||||
while (!serverTokenSource.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await serverStream.WaitForConnectionAsync(serverTokenSource.Token).ConfigureAwait(false);
|
||||
RunPacketSession(serverStream, serverTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe byte[] GetValidatedContent(NamedPipeServerStream serverStream, PipePacketHeader* header)
|
||||
{
|
||||
byte[] content = new byte[header->ContentLength];
|
||||
serverStream.ReadAtLeast(content, header->ContentLength, false);
|
||||
ThrowHelper.InvalidDataIf(XxHash64.HashToUInt64(content) != header->Checksum, "PipePacket Content Hash incorrect");
|
||||
return content;
|
||||
}
|
||||
|
||||
private unsafe void RunPacketSession(NamedPipeServerStream serverStream, CancellationToken token)
|
||||
{
|
||||
Span<byte> headerSpan = stackalloc byte[sizeof(PipePacketHeader)];
|
||||
bool sessionTerminated = false;
|
||||
while (serverStream.IsConnected && !sessionTerminated && !token.IsCancellationRequested)
|
||||
{
|
||||
serverStream.ReadExactly(headerSpan);
|
||||
fixed (byte* pHeader = headerSpan)
|
||||
{
|
||||
PipePacketHeader* header = (PipePacketHeader*)pHeader;
|
||||
|
||||
switch ((header->Type, header->Command, header->ContentType))
|
||||
{
|
||||
case (PipePacketType.Request, PipePacketCommand.RedirectActivation, PipePacketContentType.Json):
|
||||
ReadOnlySpan<byte> content = GetValidatedContent(serverStream, header);
|
||||
messageDispatcher.RedirectActivation(JsonSerializer.Deserialize<HutaoActivationArguments>(content));
|
||||
break;
|
||||
case (PipePacketType.Termination, _, _):
|
||||
serverStream.Disconnect();
|
||||
sessionTerminated = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Console;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Console;
|
||||
using static Snap.Hutao.Win32.Kernel32;
|
||||
|
||||
namespace Snap.Hutao.Core.Logging;
|
||||
|
||||
@@ -26,7 +26,7 @@ internal sealed class ConsoleWindowLifeTime : IDisposable
|
||||
SetConsoleMode(inputHandle, mode);
|
||||
}
|
||||
|
||||
SetConsoleTitle("Snap Hutao Debug Console");
|
||||
SetConsoleTitleW("Snap Hutao Debug Console");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,113 +14,99 @@ namespace Snap.Hutao.Core;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class RuntimeOptions
|
||||
{
|
||||
private readonly bool isWebView2Supported;
|
||||
private readonly string webView2Version = SH.CoreWebView2HelperVersionUndetected;
|
||||
private readonly Lazy<(Version Version, string UserAgent)> lazyVersionAndUserAgent = new(() =>
|
||||
{
|
||||
Version version = Package.Current.Id.Version.ToVersion();
|
||||
return (version, $"Snap Hutao/{version}");
|
||||
});
|
||||
|
||||
private bool? isElevated;
|
||||
private readonly Lazy<string> lazyDataFolder = new(() =>
|
||||
{
|
||||
string preferredPath = LocalSetting.Get(SettingKeys.DataFolderPath, string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(preferredPath))
|
||||
{
|
||||
Directory.CreateDirectory(preferredPath);
|
||||
return preferredPath;
|
||||
}
|
||||
|
||||
// Fallback to MyDocuments
|
||||
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
|
||||
#if RELEASE
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
#else
|
||||
// 使得迁移能正常生成
|
||||
string folderName = "Hutao";
|
||||
#endif
|
||||
string path = Path.GetFullPath(Path.Combine(myDocuments, folderName));
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
});
|
||||
|
||||
private readonly Lazy<string> lazyDeviceId = new(() =>
|
||||
{
|
||||
string userName = Environment.UserName;
|
||||
object? machineGuid = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\", "MachineGuid", userName);
|
||||
return Convert.ToMd5HexString($"{userName}{machineGuid}");
|
||||
});
|
||||
|
||||
private readonly Lazy<(string Version, bool Supported)> lazyWebViewEnvironment = new(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string version = CoreWebView2Environment.GetAvailableBrowserVersionString();
|
||||
return (version, true);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return (SH.CoreWebView2HelperVersionUndetected, false);
|
||||
}
|
||||
});
|
||||
|
||||
private readonly Lazy<bool> lazyElevated = new(() =>
|
||||
{
|
||||
if (LocalSetting.Get(SettingKeys.OverrideElevationRequirement, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||
{
|
||||
WindowsPrincipal principal = new(identity);
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
});
|
||||
|
||||
private readonly Lazy<string> lazyLocalCache = new(() => ApplicationData.Current.LocalCacheFolder.Path);
|
||||
private readonly Lazy<string> lazyInstalledLocation = new(() => Package.Current.InstalledLocation.Path);
|
||||
private readonly Lazy<string> lazyFamilyName = new(() => Package.Current.Id.FamilyName);
|
||||
|
||||
public RuntimeOptions(ILogger<RuntimeOptions> logger)
|
||||
{
|
||||
AppLaunchTime = DateTimeOffset.UtcNow;
|
||||
|
||||
DataFolder = GetDataFolderPath();
|
||||
LocalCache = ApplicationData.Current.LocalCacheFolder.Path;
|
||||
InstalledLocation = Package.Current.InstalledLocation.Path;
|
||||
FamilyName = Package.Current.Id.FamilyName;
|
||||
|
||||
Version = Package.Current.Id.Version.ToVersion();
|
||||
UserAgent = $"Snap Hutao/{Version}";
|
||||
|
||||
DeviceId = GetUniqueUserId();
|
||||
DetectWebView2Environment(logger, out webView2Version, out isWebView2Supported);
|
||||
|
||||
static string GetDataFolderPath()
|
||||
{
|
||||
string preferredPath = LocalSetting.Get(SettingKeys.DataFolderPath, string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(preferredPath))
|
||||
{
|
||||
Directory.CreateDirectory(preferredPath);
|
||||
return preferredPath;
|
||||
}
|
||||
|
||||
// Fallback to MyDocuments
|
||||
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
|
||||
#if RELEASE
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
#else
|
||||
// 使得迁移能正常生成
|
||||
string folderName = "Hutao";
|
||||
#endif
|
||||
string path = Path.GetFullPath(Path.Combine(myDocuments, folderName));
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
static string GetUniqueUserId()
|
||||
{
|
||||
string userName = Environment.UserName;
|
||||
object? machineGuid = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\", "MachineGuid", userName);
|
||||
return Convert.ToMd5HexString($"{userName}{machineGuid}");
|
||||
}
|
||||
|
||||
static void DetectWebView2Environment(ILogger<RuntimeOptions> logger, out string webView2Version, out bool isWebView2Supported)
|
||||
{
|
||||
try
|
||||
{
|
||||
webView2Version = CoreWebView2Environment.GetAvailableBrowserVersionString();
|
||||
isWebView2Supported = true;
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
webView2Version = SH.CoreWebView2HelperVersionUndetected;
|
||||
isWebView2Supported = false;
|
||||
logger.LogError(ex, "WebView2 Runtime not installed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Version Version { get; }
|
||||
public Version Version { get => lazyVersionAndUserAgent.Value.Version; }
|
||||
|
||||
public string UserAgent { get; }
|
||||
public string UserAgent { get => lazyVersionAndUserAgent.Value.UserAgent; }
|
||||
|
||||
public string InstalledLocation { get; }
|
||||
public string InstalledLocation { get => lazyInstalledLocation.Value; }
|
||||
|
||||
public string DataFolder { get; }
|
||||
public string DataFolder { get => lazyDataFolder.Value; }
|
||||
|
||||
public string LocalCache { get; }
|
||||
public string LocalCache { get => lazyLocalCache.Value; }
|
||||
|
||||
public string FamilyName { get; }
|
||||
public string FamilyName { get => lazyFamilyName.Value; }
|
||||
|
||||
public string DeviceId { get; }
|
||||
public string DeviceId { get => lazyDeviceId.Value; }
|
||||
|
||||
public string WebView2Version { get => webView2Version; }
|
||||
public string WebView2Version { get => lazyWebViewEnvironment.Value.Version; }
|
||||
|
||||
public bool IsWebView2Supported { get => isWebView2Supported; }
|
||||
public bool IsWebView2Supported { get => lazyWebViewEnvironment.Value.Supported; }
|
||||
|
||||
public bool IsElevated
|
||||
{
|
||||
get
|
||||
{
|
||||
return isElevated ??= GetElevated();
|
||||
|
||||
static bool GetElevated()
|
||||
{
|
||||
if (LocalSetting.Get(SettingKeys.OverrideElevationRequirement, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||
{
|
||||
WindowsPrincipal principal = new(identity);
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool IsElevated { get => lazyElevated.Value; }
|
||||
|
||||
public DateTimeOffset AppLaunchTime { get; }
|
||||
}
|
||||
@@ -22,7 +22,7 @@ internal static class SettingKeys
|
||||
public const string DataFolderPath = "DataFolderPath";
|
||||
public const string Major1Minor7Revision0GuideState = "Major1Minor7Revision0GuideState";
|
||||
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
|
||||
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled";
|
||||
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
|
||||
#endregion
|
||||
|
||||
#region Passport
|
||||
@@ -56,5 +56,11 @@ internal static class SettingKeys
|
||||
public const string SuppressMetadataInitialization = "SuppressMetadataInitialization";
|
||||
public const string OverrideElevationRequirement = "OverrideElevationRequirement";
|
||||
public const string OverrideUpdateVersionComparison = "OverrideUpdateVersionComparison";
|
||||
public const string OverridePackageConvertDirectoryPermissionsRequirement = "OverridePackageConvertDirectoryPermissionsRequirement";
|
||||
#endregion
|
||||
|
||||
#region Obsolete
|
||||
[Obsolete("重置调试控制台开关")]
|
||||
public const string IsAllocConsoleDebugModeEnabledLegacy1 = "IsAllocConsoleDebugModeEnabled";
|
||||
#endregion
|
||||
}
|
||||
@@ -68,7 +68,7 @@ internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
||||
|
||||
public bool IsDailyNoteRefreshEnabled()
|
||||
{
|
||||
return WScriptExists(DailyNoteRefreshScriptName, out _);
|
||||
return TaskService.Instance.RootFolder.Tasks.Any(task => task.Name is DailyNoteRefreshTaskName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.UI.Shell;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.Macros;
|
||||
using static Snap.Hutao.Win32.Ole32;
|
||||
|
||||
namespace Snap.Hutao.Core.Shell;
|
||||
|
||||
@@ -34,31 +33,44 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT result = CoCreateInstance<ShellLink, IShellLinkW>(null, CLSCTX.CLSCTX_INPROC_SERVER, out IShellLinkW shellLink);
|
||||
Marshal.ThrowExceptionForHR(result);
|
||||
return UnsafeTryCreateDesktopShoutcutForElevatedLaunch(targetLogoPath);
|
||||
}
|
||||
|
||||
shellLink.SetPath($"shell:AppsFolder\\{runtimeOptions.FamilyName}!App");
|
||||
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
|
||||
shellLink.SetIconLocation(targetLogoPath, 0);
|
||||
private unsafe bool UnsafeTryCreateDesktopShoutcutForElevatedLaunch(string targetLogoPath)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
IShellLinkDataList shellLinkDataList = (IShellLinkDataList)shellLink;
|
||||
shellLinkDataList.GetFlags(out uint flags);
|
||||
flags |= (uint)SHELL_LINK_DATA_FLAGS.SLDF_RUNAS_USER;
|
||||
shellLinkDataList.SetFlags(flags);
|
||||
|
||||
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string target = Path.Combine(desktop, $"{SH.FormatAppNameAndVersion(runtimeOptions.Version)}.lnk");
|
||||
|
||||
IPersistFile persistFile = (IPersistFile)shellLink;
|
||||
try
|
||||
// DO NOT revert if condition, COM interfaces need to be released properly
|
||||
HRESULT hr = CoCreateInstance(in ShellLink.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IShellLinkW.IID, out IShellLinkW* pShellLink);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
persistFile.Save(target, false);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return false;
|
||||
pShellLink->SetPath($"shell:AppsFolder\\{runtimeOptions.FamilyName}!App");
|
||||
pShellLink->SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
|
||||
pShellLink->SetIconLocation(targetLogoPath, 0);
|
||||
|
||||
if (SUCCEEDED(pShellLink->QueryInterface(in IShellLinkDataList.IID, out IShellLinkDataList* pShellLinkDataList)))
|
||||
{
|
||||
pShellLinkDataList->GetFlags(out uint flags);
|
||||
pShellLinkDataList->SetFlags(flags | (uint)SHELL_LINK_DATA_FLAGS.SLDF_RUNAS_USER);
|
||||
pShellLinkDataList->Release();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(pShellLink->QueryInterface(in IPersistFile.IID, out IPersistFile* pPersistFile)))
|
||||
{
|
||||
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string target = Path.Combine(desktop, $"{SH.FormatAppNameAndVersion(runtimeOptions.Version)}.lnk");
|
||||
|
||||
if (SUCCEEDED(pPersistFile->Save(target, false)))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
pPersistFile->Release();
|
||||
}
|
||||
|
||||
pShellLink->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Windowing;
|
||||
using Snap.Hutao.Win32;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.Backdrop;
|
||||
|
||||
internal interface IBackdropNeedEraseBackground;
|
||||
@@ -62,6 +62,4 @@ internal sealed class TransparentBackdrop : SystemBackdrop, IDisposable, IBackdr
|
||||
{
|
||||
disconnectedTarget.SystemBackdrop = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IBackdropNeedEraseBackground;
|
||||
}
|
||||
@@ -5,11 +5,11 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.Input.KeyboardAndMouse;
|
||||
using System.Text;
|
||||
using Windows.System;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.HotKey;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.UI.Input.KeyboardAndMouse;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.HotKey;
|
||||
|
||||
@@ -14,7 +14,7 @@ internal sealed partial class HotKeyController : IHotKeyController
|
||||
{
|
||||
private static readonly WaitCallback RunMouseClickRepeatForever = MouseClickRepeatForever;
|
||||
|
||||
private readonly object locker = new();
|
||||
private readonly object syncRoot = new();
|
||||
|
||||
private readonly HotKeyOptions hotKeyOptions;
|
||||
|
||||
@@ -40,7 +40,8 @@ internal sealed partial class HotKeyController : IHotKeyController
|
||||
|
||||
private static unsafe INPUT CreateInputForMouseEvent(MOUSE_EVENT_FLAGS flags)
|
||||
{
|
||||
INPUT input = new() { type = INPUT_TYPE.INPUT_MOUSE, };
|
||||
INPUT input = default;
|
||||
input.type = INPUT_TYPE.INPUT_MOUSE;
|
||||
input.Anonymous.mi.dwFlags = flags;
|
||||
return input;
|
||||
}
|
||||
@@ -75,7 +76,7 @@ internal sealed partial class HotKeyController : IHotKeyController
|
||||
|
||||
private void ToggleMouseClickRepeatForever()
|
||||
{
|
||||
lock (locker)
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (hotKeyOptions.IsMouseClickRepeatForeverOn)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.UI.Input.KeyboardAndMouse;
|
||||
using Windows.System;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.HotKey;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
|
||||
@@ -9,14 +9,15 @@ using Microsoft.UI.Xaml.Media;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service;
|
||||
using System.Diagnostics;
|
||||
using Snap.Hutao.Win32;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Graphics.Dwm;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.IO;
|
||||
using Windows.Graphics;
|
||||
using Windows.UI;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.DwmApi;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
@@ -105,11 +106,11 @@ internal sealed class WindowController
|
||||
return;
|
||||
}
|
||||
|
||||
WINDOWPLACEMENT windowPlacement = Win32.StructMarshal.WINDOWPLACEMENT();
|
||||
WINDOWPLACEMENT windowPlacement = WINDOWPLACEMENT.Create();
|
||||
GetWindowPlacement(options.Hwnd, ref windowPlacement);
|
||||
|
||||
// prevent save value when we are maximized.
|
||||
if (!windowPlacement.showCmd.HasFlag(SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED))
|
||||
if (!windowPlacement.ShowCmd.HasFlag(SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED))
|
||||
{
|
||||
double scale = 1.0 / options.GetRasterizationScale();
|
||||
LocalSetting.Set(SettingKeys.WindowRect, (CompactRect)window.AppWindow.GetRect().Scale(scale));
|
||||
@@ -195,7 +196,7 @@ internal sealed class WindowController
|
||||
private unsafe void UpdateImmersiveDarkMode(FrameworkElement titleBar, object discard)
|
||||
{
|
||||
BOOL isDarkMode = Control.Theme.ThemeHelper.IsDarkMode(titleBar.ActualTheme);
|
||||
DwmSetWindowAttribute(options.Hwnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, &isDarkMode, unchecked((uint)sizeof(BOOL)));
|
||||
DwmSetWindowAttribute(options.Hwnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref isDarkMode);
|
||||
}
|
||||
|
||||
private void UpdateDragRectangles()
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinRT.Interop;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
@@ -24,8 +24,8 @@ internal static class WindowExtension
|
||||
public static void SetLayeredWindow(this Window window)
|
||||
{
|
||||
HWND hwnd = (HWND)WindowNative.GetWindowHandle(window);
|
||||
nint style = GetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||
nint style = GetWindowLongPtrW(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||
style |= (nint)WINDOW_EX_STYLE.WS_EX_LAYERED;
|
||||
SetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, style);
|
||||
SetWindowLongPtrW(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, style);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Windows.Graphics;
|
||||
using Windows.Win32.Foundation;
|
||||
using WinRT.Interop;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
@@ -55,7 +55,7 @@ internal readonly struct WindowOptions
|
||||
/// <param name="persistSize">持久化尺寸</param>
|
||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false)
|
||||
{
|
||||
Hwnd = (HWND)WindowNative.GetWindowHandle(window);
|
||||
Hwnd = WindowNative.GetWindowHandle(window);
|
||||
InputNonClientPointerSource = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
|
||||
TitleBar = titleBar;
|
||||
InitSize = initSize;
|
||||
@@ -80,8 +80,8 @@ internal readonly struct WindowOptions
|
||||
{
|
||||
HWND fgHwnd = GetForegroundWindow();
|
||||
|
||||
uint threadIdHwnd = GetWindowThreadProcessId(Hwnd);
|
||||
uint threadIdFgHwnd = GetWindowThreadProcessId(fgHwnd);
|
||||
uint threadIdHwnd = GetWindowThreadProcessId(Hwnd, default);
|
||||
uint threadIdFgHwnd = GetWindowThreadProcessId(fgHwnd, default);
|
||||
|
||||
if (threadIdHwnd != threadIdFgHwnd)
|
||||
{
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
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;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.Shell;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using static Snap.Hutao.Win32.ComCtl32;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing;
|
||||
|
||||
@@ -26,8 +28,8 @@ internal sealed class WindowSubclass : IDisposable
|
||||
private readonly IHotKeyController hotKeyController;
|
||||
|
||||
// We have to explicitly hold a reference to SUBCLASSPROC
|
||||
private SUBCLASSPROC? windowProc;
|
||||
private SUBCLASSPROC? legacyDragBarProc;
|
||||
private SUBCLASSPROC windowProc = default!;
|
||||
private SUBCLASSPROC legacyDragBarProc = default!;
|
||||
|
||||
public WindowSubclass(Window window, in WindowOptions options, IServiceProvider serviceProvider)
|
||||
{
|
||||
@@ -57,7 +59,7 @@ internal sealed class WindowSubclass : IDisposable
|
||||
}
|
||||
|
||||
titleBarHooked = false;
|
||||
HWND hwndDragBar = FindWindowEx(options.Hwnd, default, "DRAG_BAR_WINDOW_CLASS", default);
|
||||
HWND hwndDragBar = FindWindowExW(options.Hwnd, default, "DRAG_BAR_WINDOW_CLASS", default);
|
||||
|
||||
if (hwndDragBar.IsNull)
|
||||
{
|
||||
@@ -76,12 +78,12 @@ internal sealed class WindowSubclass : IDisposable
|
||||
hotKeyController.UnregisterAll();
|
||||
|
||||
RemoveWindowSubclass(options.Hwnd, windowProc, WindowSubclassId);
|
||||
windowProc = null;
|
||||
windowProc = default!;
|
||||
|
||||
if (options.UseLegacyDragBarImplementation)
|
||||
{
|
||||
RemoveWindowSubclass(options.Hwnd, legacyDragBarProc, DragBarSubclassId);
|
||||
legacyDragBarProc = null;
|
||||
legacyDragBarProc = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ internal sealed class WindowSubclass : IDisposable
|
||||
{
|
||||
if (window is IMinMaxInfoHandler handler)
|
||||
{
|
||||
handler.HandleMinMaxInfo(ref *(MINMAXINFO*)lParam.Value, options.GetRasterizationScale());
|
||||
handler.HandleMinMaxInfo(ref *(MINMAXINFO*)lParam, options.GetRasterizationScale());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -116,7 +118,7 @@ internal sealed class WindowSubclass : IDisposable
|
||||
{
|
||||
if (window.SystemBackdrop is IBackdropNeedEraseBackground)
|
||||
{
|
||||
return (LRESULT)(int)(BOOL)true;
|
||||
return (LRESULT)(int)BOOL.TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -27,18 +27,4 @@ internal static class StringExtension
|
||||
{
|
||||
return source.AsSpan().TrimEnd(value).ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool EqualsAny(this string source, in ReadOnlySpan<string> values, StringComparison comparisonType)
|
||||
{
|
||||
foreach (ref readonly string value in values)
|
||||
{
|
||||
if (source.Equals(value, comparisonType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.UI.Shell;
|
||||
using Snap.Hutao.Win32.UI.Shell.Common;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.Shell.Common;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.Macros;
|
||||
using static Snap.Hutao.Win32.Ole32;
|
||||
using static Snap.Hutao.Win32.Shell32;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
@@ -21,32 +22,33 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
|
||||
public unsafe ValueResult<bool, ValueFile> PickFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters)
|
||||
{
|
||||
CoCreateInstance<FileOpenDialog, IFileOpenDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog dialog).ThrowOnFailure();
|
||||
HRESULT hr = CoCreateInstance(in FileOpenDialog.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileDialog.IID, out IFileDialog* pFileDialog);
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
}
|
||||
pFileDialog->SetOptions(options);
|
||||
SetDesktopAsStartupFolder(pFileDialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultFileName))
|
||||
{
|
||||
dialog.SetFileName(defaultFileName);
|
||||
pFileDialog->SetFileName(defaultFileName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
pFileDialog->SetTitle(title);
|
||||
}
|
||||
|
||||
if (filters is { Length: > 0 })
|
||||
{
|
||||
SetFileTypes(dialog, filters);
|
||||
SetFileTypes(pFileDialog, filters);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
HRESULT res = pFileDialog->Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default);
|
||||
@@ -56,18 +58,18 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
HRESULT t = pFileDialog->GetResult(out IShellItem* pShellItem);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
pShellItem->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new(displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
CoTaskMemFree(displayName);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
@@ -75,7 +77,8 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
|
||||
public unsafe ValueResult<bool, ValueFile> SaveFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters)
|
||||
{
|
||||
CoCreateInstance<FileSaveDialog, IFileSaveDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileSaveDialog dialog).ThrowOnFailure();
|
||||
HRESULT hr = CoCreateInstance(in FileSaveDialog.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileDialog.IID, out IFileDialog* pFileDialog);
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
@@ -83,25 +86,25 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
FILEOPENDIALOGOPTIONS.FOS_STRICTFILETYPES |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
}
|
||||
pFileDialog->SetOptions(options);
|
||||
SetDesktopAsStartupFolder(pFileDialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultFileName))
|
||||
{
|
||||
dialog.SetFileName(defaultFileName);
|
||||
pFileDialog->SetFileName(defaultFileName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
pFileDialog->SetTitle(title);
|
||||
}
|
||||
|
||||
if (filters is { Length: > 0 })
|
||||
{
|
||||
SetFileTypes(dialog, filters);
|
||||
SetFileTypes(pFileDialog, filters);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
HRESULT res = pFileDialog->Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default);
|
||||
@@ -111,18 +114,18 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
pFileDialog->GetResult(out IShellItem* pShellItem);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
pShellItem->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new(displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
CoTaskMemFree(displayName);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
@@ -130,7 +133,8 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
|
||||
public unsafe ValueResult<bool, string> PickFolder(string? title)
|
||||
{
|
||||
CoCreateInstance<FileOpenDialog, IFileOpenDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog dialog).ThrowOnFailure();
|
||||
HRESULT hr = CoCreateInstance(in FileOpenDialog.CLSID, default, CLSCTX.CLSCTX_INPROC_SERVER, in IFileDialog.IID, out IFileDialog* pFileDialog);
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
@@ -138,15 +142,15 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
pFileDialog->SetOptions(options);
|
||||
SetDesktopAsStartupFolder(pFileDialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
pFileDialog->SetTitle(title);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
HRESULT res = pFileDialog->Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default!);
|
||||
@@ -156,25 +160,24 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
pFileDialog->GetResult(out IShellItem* pShellItem);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
pShellItem->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
CoTaskMemFree(displayName);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
}
|
||||
|
||||
private static unsafe void SetFileTypes<TDialog>(TDialog dialog, (string Name, string Type)[] filters)
|
||||
where TDialog : IFileDialog
|
||||
private static unsafe void SetFileTypes(IFileDialog* pFileDialog, (string Name, string Type)[] filters)
|
||||
{
|
||||
List<nint> unmanagedStringPtrs = new(filters.Length * 2);
|
||||
List<COMDLG_FILTERSPEC> filterSpecs = new(filters.Length);
|
||||
@@ -190,10 +193,7 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
filterSpecs.Add(spec);
|
||||
}
|
||||
|
||||
fixed (COMDLG_FILTERSPEC* ptr = CollectionsMarshal.AsSpan(filterSpecs))
|
||||
{
|
||||
dialog.SetFileTypes((uint)filterSpecs.Count, ptr);
|
||||
}
|
||||
pFileDialog->SetFileTypes(CollectionsMarshal.AsSpan(filterSpecs));
|
||||
|
||||
foreach (ref readonly nint ptr in CollectionsMarshal.AsSpan(unmanagedStringPtrs))
|
||||
{
|
||||
@@ -201,11 +201,11 @@ internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInt
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void SetDesktopAsStartupFolder<TDialog>(TDialog dialog)
|
||||
where TDialog : IFileDialog
|
||||
private static unsafe void SetDesktopAsStartupFolder(IFileDialog* pFileDialog)
|
||||
{
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
SHCreateItemFromParsingName(desktopPath, default, typeof(IShellItem).GUID, out object shellItem).ThrowOnFailure();
|
||||
dialog.SetFolder((IShellItem)shellItem);
|
||||
HRESULT hr = SHCreateItemFromParsingName(desktopPath, default, in IShellItem.IID, out IShellItem* pShellItem);
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
pFileDialog->SetFolder(pShellItem);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -32,9 +32,9 @@ internal sealed partial class GuideWindow : Window, IWindowOptionsSource, IMinMa
|
||||
|
||||
public unsafe void HandleMinMaxInfo(ref MINMAXINFO info, double scalingFactor)
|
||||
{
|
||||
info.ptMinTrackSize.X = (int)Math.Max(MinWidth * scalingFactor, info.ptMinTrackSize.X);
|
||||
info.ptMinTrackSize.Y = (int)Math.Max(MinHeight * scalingFactor, info.ptMinTrackSize.Y);
|
||||
info.ptMaxTrackSize.X = (int)Math.Min(MaxWidth * scalingFactor, info.ptMaxTrackSize.X);
|
||||
info.ptMaxTrackSize.Y = (int)Math.Min(MaxHeight * scalingFactor, info.ptMaxTrackSize.Y);
|
||||
info.ptMinTrackSize.x = (int)Math.Max(MinWidth * scalingFactor, info.ptMinTrackSize.x);
|
||||
info.ptMinTrackSize.y = (int)Math.Max(MinHeight * scalingFactor, info.ptMinTrackSize.y);
|
||||
info.ptMaxTrackSize.x = (int)Math.Min(MaxWidth * scalingFactor, info.ptMaxTrackSize.x);
|
||||
info.ptMaxTrackSize.y = (int)Math.Min(MaxHeight * scalingFactor, info.ptMaxTrackSize.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Win32;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.ViewModel.Game;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -50,9 +50,9 @@ internal sealed partial class LaunchGameWindow : Window, IDisposable, IWindowOpt
|
||||
/// <inheritdoc/>
|
||||
public unsafe void HandleMinMaxInfo(ref MINMAXINFO info, double scalingFactor)
|
||||
{
|
||||
info.ptMinTrackSize.X = (int)Math.Max(MinWidth * scalingFactor, info.ptMinTrackSize.X);
|
||||
info.ptMinTrackSize.Y = (int)Math.Max(MinHeight * scalingFactor, info.ptMinTrackSize.Y);
|
||||
info.ptMaxTrackSize.X = (int)Math.Min(MaxWidth * scalingFactor, info.ptMaxTrackSize.X);
|
||||
info.ptMaxTrackSize.Y = (int)Math.Min(MaxHeight * scalingFactor, info.ptMaxTrackSize.Y);
|
||||
info.ptMinTrackSize.x = (int)Math.Max(MinWidth * scalingFactor, info.ptMinTrackSize.x);
|
||||
info.ptMinTrackSize.y = (int)Math.Max(MinHeight * scalingFactor, info.ptMinTrackSize.y);
|
||||
info.ptMaxTrackSize.x = (int)Math.Min(MaxWidth * scalingFactor, info.ptMaxTrackSize.x);
|
||||
info.ptMaxTrackSize.y = (int)Math.Min(MaxHeight * scalingFactor, info.ptMaxTrackSize.y);
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,18 @@
|
||||
x:Class="Snap.Hutao.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shv="using:Snap.Hutao.View"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<shv:MainView/>
|
||||
|
||||
<shv:TitleView
|
||||
x:Name="TitleBarView"
|
||||
Height="44"
|
||||
Margin="48,0,0,0"/>
|
||||
Margin="44,0,0,0"/>
|
||||
|
||||
<shv:MainView/>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -37,7 +37,7 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IMinMax
|
||||
/// <inheritdoc/>
|
||||
public unsafe void HandleMinMaxInfo(ref MINMAXINFO pInfo, double scalingFactor)
|
||||
{
|
||||
pInfo.ptMinTrackSize.X = (int)Math.Max(MinWidth * scalingFactor, pInfo.ptMinTrackSize.X);
|
||||
pInfo.ptMinTrackSize.Y = (int)Math.Max(MinHeight * scalingFactor, pInfo.ptMinTrackSize.Y);
|
||||
pInfo.ptMinTrackSize.x = (int)Math.Max(MinWidth * scalingFactor, pInfo.ptMinTrackSize.x);
|
||||
pInfo.ptMinTrackSize.y = (int)Math.Max(MinHeight * scalingFactor, pInfo.ptMinTrackSize.y);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
using Microsoft.UI;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Win32;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
@@ -13,43 +13,118 @@ internal static class Materials
|
||||
{
|
||||
public static FrozenSet<MaterialId> MondayThursdayItems { get; } = FrozenSet.ToFrozenSet<MaterialId>(
|
||||
[
|
||||
104301U, 104302U, 104303U, // 「自由」
|
||||
104310U, 104311U, 104312U, // 「繁荣」
|
||||
104320U, 104321U, 104322U, // 「浮世」
|
||||
104329U, 104330U, 104331U, // 「诤言」
|
||||
104338U, 104339U, 104340U, // 「公平」
|
||||
114001U, 114002U, 114003U, 114004U, // 高塔孤王
|
||||
114013U, 114014U, 114015U, 114016U, // 孤云寒林
|
||||
114025U, 114026U, 114027U, 114028U, // 远海夷地
|
||||
114037U, 114038U, 114039U, 114040U, // 谧林涓露
|
||||
114049U, 114050U, 114051U, 114052U, // 悠古弦音
|
||||
104301U,
|
||||
104302U,
|
||||
104303U, // 「自由」
|
||||
104310U,
|
||||
104311U,
|
||||
104312U, // 「繁荣」
|
||||
104320U,
|
||||
104321U,
|
||||
104322U, // 「浮世」
|
||||
104329U,
|
||||
104330U,
|
||||
104331U, // 「诤言」
|
||||
104338U,
|
||||
104339U,
|
||||
104340U, // 「公平」
|
||||
114001U,
|
||||
114002U,
|
||||
114003U,
|
||||
114004U, // 高塔孤王
|
||||
114013U,
|
||||
114014U,
|
||||
114015U,
|
||||
114016U, // 孤云寒林
|
||||
114025U,
|
||||
114026U,
|
||||
114027U,
|
||||
114028U, // 远海夷地
|
||||
114037U,
|
||||
114038U,
|
||||
114039U,
|
||||
114040U, // 谧林涓露
|
||||
114049U,
|
||||
114050U,
|
||||
114051U,
|
||||
114052U, // 悠古弦音
|
||||
]);
|
||||
|
||||
public static FrozenSet<MaterialId> TuesdayFridayItems { get; } = FrozenSet.ToFrozenSet<MaterialId>(
|
||||
[
|
||||
104304U, 104305U, 104306U, // 「抗争」
|
||||
104313U, 104314U, 104315U, // 「勤劳」
|
||||
104323U, 104324U, 104325U, // 「风雅」
|
||||
104332U, 104333U, 104334U, // 「巧思」
|
||||
104341U, 104342U, 104343U, // 「正义」
|
||||
114005U, 114006U, 114007U, 114008U, // 凛风奔狼
|
||||
114017U, 114018U, 114019U, 114020U, // 雾海云间
|
||||
114029U, 114030U, 114031U, 114032U, // 鸣神御灵
|
||||
114041U, 114042U, 114043U, 114044U, // 绿洲花园
|
||||
114053U, 114054U, 114055U, 114056U, // 纯圣露滴
|
||||
104304U,
|
||||
104305U,
|
||||
104306U, // 「抗争」
|
||||
104313U,
|
||||
104314U,
|
||||
104315U, // 「勤劳」
|
||||
104323U,
|
||||
104324U,
|
||||
104325U, // 「风雅」
|
||||
104332U,
|
||||
104333U,
|
||||
104334U, // 「巧思」
|
||||
104341U,
|
||||
104342U,
|
||||
104343U, // 「正义」
|
||||
114005U,
|
||||
114006U,
|
||||
114007U,
|
||||
114008U, // 凛风奔狼
|
||||
114017U,
|
||||
114018U,
|
||||
114019U,
|
||||
114020U, // 雾海云间
|
||||
114029U,
|
||||
114030U,
|
||||
114031U,
|
||||
114032U, // 鸣神御灵
|
||||
114041U,
|
||||
114042U,
|
||||
114043U,
|
||||
114044U, // 绿洲花园
|
||||
114053U,
|
||||
114054U,
|
||||
114055U,
|
||||
114056U, // 纯圣露滴
|
||||
]);
|
||||
|
||||
public static FrozenSet<MaterialId> WednesdaySaturdayItems { get; } = FrozenSet.ToFrozenSet<MaterialId>(
|
||||
[
|
||||
104307U, 104308U, 104309U, // 「诗文」
|
||||
104316U, 104317U, 104318U, // 「黄金」
|
||||
104326U, 104327U, 104328U, // 「天光」
|
||||
104335U, 104336U, 104337U, // 「笃行」
|
||||
104344U, 104345U, 104346U, // 「秩序」
|
||||
114009U, 114010U, 114011U, 114012U, // 狮牙斗士
|
||||
114021U, 114022U, 114023U, 114024U, // 漆黑陨铁
|
||||
114033U, 114034U, 114035U, 114036U, // 今昔剧画
|
||||
114045U, 114046U, 114047U, 114048U, // 谧林涓露
|
||||
114057U, 114058U, 114059U, 114060U, // 无垢之海
|
||||
104307U,
|
||||
104308U,
|
||||
104309U, // 「诗文」
|
||||
104316U,
|
||||
104317U,
|
||||
104318U, // 「黄金」
|
||||
104326U,
|
||||
104327U,
|
||||
104328U, // 「天光」
|
||||
104335U,
|
||||
104336U,
|
||||
104337U, // 「笃行」
|
||||
104344U,
|
||||
104345U,
|
||||
104346U, // 「秩序」
|
||||
114009U,
|
||||
114010U,
|
||||
114011U,
|
||||
114012U, // 狮牙斗士
|
||||
114021U,
|
||||
114022U,
|
||||
114023U,
|
||||
114024U, // 漆黑陨铁
|
||||
114033U,
|
||||
114034U,
|
||||
114035U,
|
||||
114036U, // 今昔剧画
|
||||
114045U,
|
||||
114046U,
|
||||
114047U,
|
||||
114048U, // 谧林涓露
|
||||
114057U,
|
||||
114058U,
|
||||
114059U,
|
||||
114060U, // 无垢之海
|
||||
]);
|
||||
}
|
||||
@@ -82,4 +82,7 @@ internal enum WaveType
|
||||
|
||||
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave1Additional))]
|
||||
Wave1Additional = 1999,
|
||||
|
||||
[LocalizationKey(nameof(SH.ModelMetadataTowerWaveTypeWave99999))]
|
||||
Wave99999 = 99999,
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutao"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.4.0" />
|
||||
Version="1.9.5.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao</DisplayName>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutaoDev"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.4.0" />
|
||||
Version="1.9.5.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao Dev</DisplayName>
|
||||
|
||||
@@ -19,6 +19,22 @@ public static partial class Program
|
||||
{
|
||||
private static readonly ApplicationInitializationCallback AppInitializationCallback = InitializeApp;
|
||||
|
||||
[ModuleInitializer]
|
||||
internal static void InitializeModule()
|
||||
{
|
||||
// Set base directory env var for PublishSingleFile support (referenced by SxS redirection)
|
||||
Environment.SetEnvironmentVariable("MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", AppContext.BaseDirectory);
|
||||
|
||||
// No error handling needed as the target function does nothing (just {return S_OK}).
|
||||
// It's the act of calling the function causing the DllImport to load the DLL that
|
||||
// matters. This provides the moral equivalent of a native DLL's Import Address
|
||||
// Table (IAT) have an entry that's resolved when this module is loaded.
|
||||
_ = WindowsAppRuntimeEnsureIsLoaded();
|
||||
}
|
||||
|
||||
[LibraryImport("Microsoft.WindowsAppRuntime.dll", EntryPoint = "WindowsAppRuntime_EnsureIsLoaded")]
|
||||
private static partial int WindowsAppRuntimeEnsureIsLoaded();
|
||||
|
||||
[LibraryImport("Microsoft.ui.xaml.dll")]
|
||||
private static partial void XamlCheckProcessRequirements();
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -247,7 +247,7 @@
|
||||
<value>Not refreshed</value>
|
||||
</data>
|
||||
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
|
||||
<value>Refresh at {0:MM.dd HH:mm:ss}</value>
|
||||
<value>Refreshed at {0:MM.dd HH:mm:ss}</value>
|
||||
</data>
|
||||
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
|
||||
<value>Schedule {0}</value>
|
||||
@@ -738,10 +738,10 @@
|
||||
<value>Avatar Calculator: {0:MM-dd HH:mm}</value>
|
||||
</data>
|
||||
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
|
||||
<value>My Characters: N/A</value>
|
||||
<value>Battle Chronicle: Not Refreshed</value>
|
||||
</data>
|
||||
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
|
||||
<value>My Characters: {0:MM-dd HH:mm}</value>
|
||||
<value>Battle Chronicle: {0:MM-dd HH:mm}</value>
|
||||
</data>
|
||||
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
|
||||
<value>Enka: N/A</value>
|
||||
@@ -870,11 +870,23 @@
|
||||
<value>No writing permission in file system, unable to start the server conversion.</value>
|
||||
</data>
|
||||
<data name="ServiceGameEnsureGameResourceQueryResourceInformation" xml:space="preserve">
|
||||
<value>Querying Game Resource Information</value>
|
||||
<value>Download game resource index</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>
|
||||
@@ -1158,7 +1170,7 @@
|
||||
<value>Realm Currency Alarm Threshold</value>
|
||||
</data>
|
||||
<data name="ViewDialogDailyNoteNotificationResinNotifyThreshold" xml:space="preserve">
|
||||
<value>Realm Currency Alarm Threshold</value>
|
||||
<value>Original Resin Alarm Threshold</value>
|
||||
</data>
|
||||
<data name="ViewDialogDailyNoteNotificationShowInHomeWidget" xml:space="preserve">
|
||||
<value>Show widget on Home page</value>
|
||||
@@ -1175,6 +1187,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>Realtime Note Webhook URL</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>You need other tools to restore the loopback after it is exempted</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>Confirm to Config Loopback Exemption</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>Import wish history</value>
|
||||
</data>
|
||||
@@ -1271,6 +1289,12 @@
|
||||
<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 <b>title name</b> 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>
|
||||
@@ -1292,6 +1316,9 @@
|
||||
<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>
|
||||
@@ -1368,7 +1395,7 @@
|
||||
<value>This operation is irreversible. The achievement archive will be lost.</value>
|
||||
</data>
|
||||
<data name="ViewModelAchievementRemoveArchiveTitle" xml:space="preserve">
|
||||
<value>Are you sure you want to delete archive {0}?</value>
|
||||
<value>Are you sure to delete archive {0}?</value>
|
||||
</data>
|
||||
<data name="ViewModelAchievementUIAFExportPickerTitle" xml:space="preserve">
|
||||
<value>Export UIAF Json file to the selected path</value>
|
||||
@@ -1430,6 +1457,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>HoYoLab account does not support Realtime Notes verification</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>Failed to modify Scheduled Task</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30 min | 3.75 Resin</value>
|
||||
</data>
|
||||
@@ -1445,14 +1475,11 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8 min | 1 Resin</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>Failed to add Scheduled Task, please try again in administrator mode</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>Fetching Realtime Notes data, please wait</value>
|
||||
</data>
|
||||
<data name="ViewModelExportSuccessMessage" xml:space="preserve">
|
||||
<value>Successfully saved to selected patch</value>
|
||||
<value>Successfully saved to selected path</value>
|
||||
</data>
|
||||
<data name="ViewModelExportSuccessTitle" xml:space="preserve">
|
||||
<value>Export successfully</value>
|
||||
@@ -1491,7 +1518,7 @@
|
||||
<value>Failed to fetch wish history</value>
|
||||
</data>
|
||||
<data name="ViewModelGachaLogRefreshOperationCancel" xml:space="preserve">
|
||||
<value>Wish history refresh is canceled unexpectedly</value>
|
||||
<value>Wish history refresh was canceled unexpectedly</value>
|
||||
</data>
|
||||
<data name="ViewModelGachaLogRemoveArchiveDescription" xml:space="preserve">
|
||||
<value>This operation is irreversible. The wish history archive will be lost.</value>
|
||||
@@ -1541,6 +1568,9 @@
|
||||
<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>
|
||||
@@ -1574,6 +1604,12 @@
|
||||
<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>
|
||||
@@ -1626,7 +1662,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>
|
||||
@@ -1647,7 +1683,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>
|
||||
@@ -1671,7 +1707,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>
|
||||
@@ -1698,7 +1734,7 @@
|
||||
<value>Sync character talents data</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>Sync from MiHoYo BBS My Characters</value>
|
||||
<value>Sync from MiHoYo BBS Battle Chronicle</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>Sync most data other than character talent</value>
|
||||
@@ -1722,7 +1758,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>
|
||||
@@ -1823,6 +1859,48 @@
|
||||
<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="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>Exempted</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>Config Loopback Exemption</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>
|
||||
@@ -1875,7 +1953,7 @@
|
||||
<value>Input</value>
|
||||
</data>
|
||||
<data name="ViewPageGachaLogRecoverFromHutaoCloudDescription" xml:space="preserve">
|
||||
<value>Recover Wish Record from Snap Hutao Cloud</value>
|
||||
<value>Recover Wish Records from Snap Hutao Cloud</value>
|
||||
</data>
|
||||
<data name="ViewPageGachaLogRefresh" xml:space="preserve">
|
||||
<value>Refresh</value>
|
||||
@@ -2055,10 +2133,10 @@
|
||||
<value>Borderless</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameAppearanceCloudThirdPartyMobileDescription" xml:space="preserve">
|
||||
<value>Enable touchscreen layout, but the keyboard & mouse are no longer usable.</value>
|
||||
<value>Enable touchscreen layout, but the keyboard & 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>
|
||||
@@ -2088,7 +2166,7 @@
|
||||
<value>Modify its default behavior at game startup</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameArgumentsHeader" xml:space="preserve">
|
||||
<value>Start-up Arguments</value>
|
||||
<value>Launch Parameters</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>General</value>
|
||||
@@ -2142,7 +2220,7 @@
|
||||
<value>Resource Download</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>Client</value>
|
||||
<value>Full Package</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>Pre-download</value>
|
||||
@@ -2192,6 +2270,12 @@
|
||||
<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>
|
||||
@@ -2205,7 +2289,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>
|
||||
@@ -2409,7 +2493,7 @@
|
||||
<value>After a full reading of the Genshin Impact and Snap Hutao user agreements, I choose to enable「Game Launcher - Advanced Features」.</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingIsAdvancedLaunchOptionsEnabledHeader" xml:space="preserve">
|
||||
<value>Enable Advanced Features</value>
|
||||
<value>Advanced Features</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingKeyShortcutAutoClickingDescription" xml:space="preserve">
|
||||
<value>Change Auto Click Shortcut</value>
|
||||
@@ -2520,7 +2604,7 @@
|
||||
<value>Quotes</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarSpecialFoodTitle" xml:space="preserve">
|
||||
<value>Special Food</value>
|
||||
<value>Special Dish</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarStoriesHeader" xml:space="preserve">
|
||||
<value>Stories</value>
|
||||
@@ -2564,9 +2648,18 @@
|
||||
<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>
|
||||
@@ -2661,7 +2754,7 @@
|
||||
<value>Web Login</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationLoginQRCodeAction" xml:space="preserve">
|
||||
<value>Login via scanning QR code</value>
|
||||
<value>Login via QR code</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
|
||||
<value>Input Manually</value>
|
||||
@@ -2747,6 +2840,9 @@
|
||||
<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>
|
||||
@@ -2811,10 +2907,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>
|
||||
@@ -2847,7 +2943,7 @@
|
||||
<value>{0} Seconds</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
|
||||
<value>Verification failed. Please check MiHoYo BBS - My Character - Realtime Notes manually</value>
|
||||
<value>Verification failed. Please check MiHoYo BBS - Toolbox - Realtime Notes manually</value>
|
||||
</data>
|
||||
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
|
||||
<value>Wrong UID format</value>
|
||||
@@ -2916,7 +3012,7 @@
|
||||
<value>Snap Hutao server is under maintenance</value>
|
||||
</data>
|
||||
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
|
||||
<value>Verification failed. Please verify manually or check MiHoYo BBS - My Characters page</value>
|
||||
<value>Verification failed. Please verify manually or check MiHoYo BBS - Battle Chronicle page</value>
|
||||
</data>
|
||||
<data name="WebResponseFormat" xml:space="preserve">
|
||||
<value>Return Code: {0} | Message: {1}</value>
|
||||
@@ -2927,4 +3023,7 @@
|
||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||
<value>[{1}] network request exception in [{0}] please try again later</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
||||
<value>Monitor ID</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<value>Snap Hutao Dev {0}</value>
|
||||
</data>
|
||||
<data name="AppElevatedDevNameAndVersion" xml:space="preserve">
|
||||
<value>Snap Hutao Dev {0} [Administrator]</value>
|
||||
<value>胡桃Dev {0} [管理员]</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>Karakter Saya: N/A</value>
|
||||
<value>Battle Chronicle: Belum Disegarkan</value>
|
||||
</data>
|
||||
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
|
||||
<value>Karakter Saya: {0:MM-dd HH:mm}</value>
|
||||
<value>Battle Chronicle: {0:MM-dd HH:mm}</value>
|
||||
</data>
|
||||
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
|
||||
<value>Enka: N/A</value>
|
||||
@@ -870,11 +870,23 @@
|
||||
<value>Tidak ada izin menulis dalam sistem berkas, tidak dapat memulai konversi server.</value>
|
||||
</data>
|
||||
<data name="ServiceGameEnsureGameResourceQueryResourceInformation" xml:space="preserve">
|
||||
<value>Mencari Informasi Sumber Daya Game</value>
|
||||
<value>Unduh indeks 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>
|
||||
@@ -1175,6 +1187,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>Catatan Realtime Webhook URL</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>Mengimpor riwayat wish</value>
|
||||
</data>
|
||||
@@ -1271,6 +1289,12 @@
|
||||
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
|
||||
<value>Pindai kode QR dengan Aplikasi MiHoYo BBS</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
|
||||
<value>Untuk menghindari mengaktifkan secara keliru, harap masukkan <b>nama judul</b> dari fitur yang Anda aktifkan</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>
|
||||
@@ -1292,6 +1316,9 @@
|
||||
<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>
|
||||
@@ -1430,6 +1457,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>Akun HoYoLab tidak mendukung verifikasi Catatan Realtime.</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>Gagal mengubah tugas terjadwal</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30 min | 3.75 Resin</value>
|
||||
</data>
|
||||
@@ -1445,9 +1475,6 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8 min | 1 Resin</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>Gagal menambahkan Tugas Terjadwal, silakan coba lagi dalam mode administrator.</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>Mengambil data Catatan Realtime, mohon tunggu.</value>
|
||||
</data>
|
||||
@@ -1541,6 +1568,9 @@
|
||||
<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>
|
||||
@@ -1574,6 +1604,12 @@
|
||||
<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>
|
||||
@@ -1698,7 +1734,7 @@
|
||||
<value>Sinkronisasi Data Talenta Karakter</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>Sinkronkan dari Karakter Saya MiHoYo BBS</value>
|
||||
<value>Sinkronisasi dari MiHoYo BBS Battle Chronicle</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>Sinkronkan sebagian besar data kecuali talent karakter.</value>
|
||||
@@ -1823,6 +1859,48 @@
|
||||
<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="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||
<value>当前代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||
<value>无代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>解除 Loopback 限制</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>Kami selalu memberikan prioritas pada masalah yang dilaporkan di GitHub.</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackRoadmapDescription" xml:space="preserve">
|
||||
<value>Roadmap Pengembangan</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackSearchResultPlaceholderTitle" xml:space="preserve">
|
||||
<value>Tidak ada hasil</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>
|
||||
@@ -2142,7 +2220,7 @@
|
||||
<value>Pengunduhan Sumber Daya</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>Klien</value>
|
||||
<value>完整包</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>Prapengunduhan</value>
|
||||
@@ -2192,6 +2270,12 @@
|
||||
<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>
|
||||
@@ -2564,9 +2648,18 @@
|
||||
<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>
|
||||
@@ -2747,6 +2840,9 @@
|
||||
<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>
|
||||
@@ -2847,7 +2943,7 @@
|
||||
<value>{0} detik</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
|
||||
<value>Verifikasi gagal. Silakan periksa MiHoYo BBS - Karakter Saya - Catatan Realtime secara manual.</value>
|
||||
<value>Verifikasi gagal. Harap periksa MiHoYo BBS - Toolbox - Catatan Real-time secara manual.</value>
|
||||
</data>
|
||||
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
|
||||
<value>Format UID Salah</value>
|
||||
@@ -2916,7 +3012,7 @@
|
||||
<value>Server Snap Hutao sedang dalam perbaikan</value>
|
||||
</data>
|
||||
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
|
||||
<value>Verifikasi gagal. Harap verifikasi secara manual atau periksa halaman Karakter Saya di MiHoYo BBS.</value>
|
||||
<value>Verifikasi gagal. Harap verifikasi secara manual atau periksa halaman MiHoYo BBS - Battle Chronicle.</value>
|
||||
</data>
|
||||
<data name="WebResponseFormat" xml:space="preserve">
|
||||
<value>Kode Kembali: {0} | Pesan: {1}</value>
|
||||
@@ -2927,4 +3023,7 @@
|
||||
<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>
|
||||
@@ -121,7 +121,7 @@
|
||||
<value>胡桃 Dev {0}</value>
|
||||
</data>
|
||||
<data name="AppElevatedDevNameAndVersion" xml:space="preserve">
|
||||
<value>胡桃Dev {0} [管理者]</value>
|
||||
<value>胡桃 Dev {0} [管理者]</value>
|
||||
</data>
|
||||
<data name="AppElevatedNameAndVersion" 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,11 +870,23 @@
|
||||
<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>
|
||||
@@ -1175,6 +1187,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>リアルタイムノートのWebhook URL</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>祈願記録をインポート</value>
|
||||
</data>
|
||||
@@ -1271,6 +1289,12 @@
|
||||
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
|
||||
<value>MiHoYo BBS を使用して QR コードをスキャンします</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
|
||||
<value>謝って有効にしないようにするためには、有効にする機能の<b>タイトル名</b>を入力してください</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
|
||||
<value>危険な機能を有効にしています</value>
|
||||
</data>
|
||||
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
|
||||
<value>この操作は取り消せません。すべてのユーザーのログイン状態が解除されます。</value>
|
||||
</data>
|
||||
@@ -1292,6 +1316,9 @@
|
||||
<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>
|
||||
@@ -1430,6 +1457,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>HoYoLabユーザーのリアルタイムノートはサポートしていません。</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>スケジュールされたタスクの変更に失敗しました</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30 分 | 3.75樹脂</value>
|
||||
</data>
|
||||
@@ -1445,9 +1475,6 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8 分 | 1樹脂</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>タスク スケジューラーへの追加に失敗しました。管理者モードで再度お試しください。</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>リアルタイムノートの情報を取得中、しばらくお待ちください</value>
|
||||
</data>
|
||||
@@ -1541,6 +1568,9 @@
|
||||
<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>
|
||||
@@ -1574,6 +1604,12 @@
|
||||
<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>
|
||||
@@ -1698,7 +1734,7 @@
|
||||
<value>キャラクターの天賦情報を同期</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>MiHoYo BBSから所持キャラを同期</value>
|
||||
<value>MiHoYo BBSから原神の記録を同期</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>キャラ天賦以外の情報を概ね同期</value>
|
||||
@@ -1823,6 +1859,48 @@
|
||||
<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="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||
<value>当前代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||
<value>无代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>解除 Loopback 限制</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>
|
||||
@@ -2142,7 +2220,7 @@
|
||||
<value>リソースダウンロード</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>クライアント</value>
|
||||
<value>完整包</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>事前ダウンロード</value>
|
||||
@@ -2192,6 +2270,12 @@
|
||||
<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>
|
||||
@@ -2205,7 +2289,7 @@
|
||||
<value>スクリーンショットフォルダを開く</value>
|
||||
</data>
|
||||
<data name="ViewPageResetGamePathAction" xml:space="preserve">
|
||||
<value>ゲームのフォルダを選択してください。</value>
|
||||
<value>ゲームフォルダを選択</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingAboutHeader" xml:space="preserve">
|
||||
<value>胡桃について</value>
|
||||
@@ -2564,9 +2648,18 @@
|
||||
<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>
|
||||
@@ -2747,6 +2840,9 @@
|
||||
<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>
|
||||
@@ -2847,7 +2943,7 @@
|
||||
<value>{0} 秒</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
|
||||
<value>認証に失敗しました。「MiHoYo BBS - 戦績ツール - リアルタイムノート」で確認し、認証を行ってください</value>
|
||||
<value>認証に失敗しました。「MiHoYo BBS - 戦績ツール - リアルタイムノート」で確認してください</value>
|
||||
</data>
|
||||
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
|
||||
<value>UIDは正しくありません</value>
|
||||
@@ -2916,7 +3012,7 @@
|
||||
<value>胡桃サーバがメンテナンス中です</value>
|
||||
</data>
|
||||
<data name="WebIndexOrSpiralAbyssVerificationFailed" xml:space="preserve">
|
||||
<value>認証に失敗しました。 手動で認証するか、MiHoYo BBS - 戦績 を確認してください。</value>
|
||||
<value>認証に失敗しました。 手動で認証するか、MiHoYo BBS - 戦績 - マイ キャラクター を確認してください。</value>
|
||||
</data>
|
||||
<data name="WebResponseFormat" xml:space="preserve">
|
||||
<value>リターンコード:{0} | メッセージ:{1}</value>
|
||||
@@ -2927,4 +3023,7 @@
|
||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||
<value>[{0}] の[{1}] のリクエストにエラーが発生、時間をおいてから試してください</value>
|
||||
</data>
|
||||
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
||||
<value>モニターID</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -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,11 +870,23 @@
|
||||
<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>
|
||||
@@ -1175,6 +1187,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>实时便笺 Webhook Url</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>기원 기록 가져오기</value>
|
||||
</data>
|
||||
@@ -1271,6 +1289,12 @@
|
||||
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
|
||||
<value>使用米游社扫描二维码</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
|
||||
<value>为防止你在无意间启用,请输入正在启用的功能开关的<b>标题名称</b></value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
|
||||
<value>你正在启用一个危险功能</value>
|
||||
</data>
|
||||
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
|
||||
<value>이 작업은 되돌릴 수 없으며, 모든 사용자 로그인 상태가 해제됩니다</value>
|
||||
</data>
|
||||
@@ -1292,6 +1316,9 @@
|
||||
<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>
|
||||
@@ -1430,6 +1457,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>HoYoLab 계정은 실시간 메모 확인 기능을 지원하지 않습니다</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>예약된 작업을 수정하지 못했습니다</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30분 | 3.75 레진</value>
|
||||
</data>
|
||||
@@ -1445,9 +1475,6 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8분 | 1 레진</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>작업 등록에 실패했습니다. 관리자 모드로 실행하세요</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>正在获取实时便笺信息,请稍候</value>
|
||||
</data>
|
||||
@@ -1541,6 +1568,9 @@
|
||||
<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>
|
||||
@@ -1574,6 +1604,12 @@
|
||||
<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>
|
||||
@@ -1698,7 +1734,7 @@
|
||||
<value>캐릭터 특성 정보 동기화</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>HoYoLAB에서 내 캐릭터 동기화</value>
|
||||
<value>从米游社原神战绩同步</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>캐릭터 특성을 제외한 대부분의 정보 동기화</value>
|
||||
@@ -1823,6 +1859,48 @@
|
||||
<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="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>解除 Loopback 限制</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>
|
||||
@@ -2142,7 +2220,7 @@
|
||||
<value>리소스 다운로드</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>클라이언트</value>
|
||||
<value>完整包</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>사전 다운로드</value>
|
||||
@@ -2192,6 +2270,12 @@
|
||||
<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>
|
||||
@@ -2564,9 +2648,18 @@
|
||||
<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>
|
||||
@@ -2747,6 +2840,9 @@
|
||||
<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>
|
||||
@@ -2847,7 +2943,7 @@
|
||||
<value>{0}초</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteVerificationFailed" xml:space="preserve">
|
||||
<value>인증에 실패했습니다. 수동으로 인증하거나 'HoYoLAB-전적-실시간 메모' 페이지에서 확인하시기 바랍니다.</value>
|
||||
<value>验证失败,请手动验证或前往「米游社-旅行工具-原神战绩-实时便笺」页面查看</value>
|
||||
</data>
|
||||
<data name="WebEnkaResponseStatusCode400" xml:space="preserve">
|
||||
<value>错误的 UID 格式</value>
|
||||
@@ -2916,7 +3012,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>
|
||||
@@ -2927,4 +3023,7 @@
|
||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
||||
</data>
|
||||
<data name="WindowIdentifyMonitorHeader" xml:space="preserve">
|
||||
<value>显示器编号</value>
|
||||
</data>
|
||||
</root>
|
||||
3029
src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.pt.resx
Normal file
3029
src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.pt.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -159,6 +159,18 @@
|
||||
<data name="ControlPanelPanelSelectorDropdownListName" xml:space="preserve">
|
||||
<value>列表</value>
|
||||
</data>
|
||||
<data name="ControlTextMetadataSpecialNameMaleFemale" xml:space="preserve">
|
||||
<value>旅行者(男):$1\r\n旅行者(女):$2</value>
|
||||
</data>
|
||||
<data name="ControlTextMetadataSpecialNameMetaAvatarSexProD" xml:space="preserve">
|
||||
<value>王子/公主</value>
|
||||
</data>
|
||||
<data name="ControlTextMetadataSpecialNamePlayerAvatarSexPro" xml:space="preserve">
|
||||
<value>他/她</value>
|
||||
</data>
|
||||
<data name="ControlTextMetadataSpecialNameRealNameId1" xml:space="preserve">
|
||||
<value>流浪者</value>
|
||||
</data>
|
||||
<data name="CoreExceptionServiceDatabaseCorruptedMessage" xml:space="preserve">
|
||||
<value>数据库已损坏:{0}</value>
|
||||
</data>
|
||||
@@ -497,6 +509,9 @@
|
||||
<data name="ModelMetadataTowerWaveTypeWave4" xml:space="preserve">
|
||||
<value>第四波:击败所有怪物,下一波才会出现</value>
|
||||
</data>
|
||||
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
||||
<value>维持场上 4 个盗宝团怪物,击杀后立即替换,总数 12 个</value>
|
||||
</data>
|
||||
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
||||
<value>请更新角色橱窗数据</value>
|
||||
</data>
|
||||
@@ -738,10 +753,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>
|
||||
@@ -1187,6 +1202,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>实时便笺 Webhook Url</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>导入祈愿记录</value>
|
||||
</data>
|
||||
@@ -1284,7 +1305,7 @@
|
||||
<value>使用米游社扫描二维码</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
|
||||
<value>请输入你正在启用的功能标题</value>
|
||||
<value>为防止你在无意间启用,请输入正在启用的功能开关的<b>标题名称</b></value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
|
||||
<value>你正在启用一个危险功能</value>
|
||||
@@ -1451,6 +1472,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>HoYoLab 账号不支持验证实时便笺</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>修改计划任务失败</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30 分钟 | 3.75 树脂</value>
|
||||
</data>
|
||||
@@ -1466,9 +1490,6 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8 分钟 | 1 树脂</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>注册计划任务失败,请使用管理员模式重试</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>正在获取实时便笺信息,请稍候</value>
|
||||
</data>
|
||||
@@ -1728,7 +1749,7 @@
|
||||
<value>同步角色天赋信息</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>从米游社我的角色同步</value>
|
||||
<value>从米游社原神战绩同步</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>同步角色天赋外的大部分信息</value>
|
||||
@@ -1862,6 +1883,18 @@
|
||||
<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="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
||||
<value>与我们密切联系</value>
|
||||
</data>
|
||||
@@ -1869,11 +1902,14 @@
|
||||
<value>功能指南</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackGithubIssuesDescription" xml:space="preserve">
|
||||
<value>我们总是优先处理 Github 上的问题</value>
|
||||
<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>
|
||||
@@ -1971,7 +2007,7 @@
|
||||
<value>总览</value>
|
||||
</data>
|
||||
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
|
||||
<value>统计</value>
|
||||
<value>全球祈愿统计</value>
|
||||
</data>
|
||||
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
|
||||
<value>武器</value>
|
||||
@@ -2199,7 +2235,7 @@
|
||||
<value>资源下载</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>客户端</value>
|
||||
<value>完整包</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>预下载</value>
|
||||
@@ -2922,7 +2958,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>
|
||||
@@ -2991,7 +3027,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>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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{0}</value>
|
||||
<value>HTTP GET {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,11 +870,23 @@
|
||||
<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>
|
||||
@@ -885,13 +897,13 @@
|
||||
<value>遊戲進程已啟動</value>
|
||||
</data>
|
||||
<data name="ServiceGameLaunchPhaseUnlockFpsFailed" xml:space="preserve">
|
||||
<value>解鎖幀率上限失敗,正在結束遊戲進程</value>
|
||||
<value>解鎖 FPS 上限失敗,正在結束遊戲行程</value>
|
||||
</data>
|
||||
<data name="ServiceGameLaunchPhaseUnlockFpsSucceed" xml:space="preserve">
|
||||
<value>解鎖幀率上限成功</value>
|
||||
<value>解鎖 FPS 上限成功</value>
|
||||
</data>
|
||||
<data name="ServiceGameLaunchPhaseUnlockingFps" xml:space="preserve">
|
||||
<value>正在嘗試解鎖幀率上限</value>
|
||||
<value>正在嘗試解鎖 FPS 上限</value>
|
||||
</data>
|
||||
<data name="ServiceGameLaunchPhaseWaitingProcessExit" xml:space="preserve">
|
||||
<value>等待遊戲進程退出</value>
|
||||
@@ -1175,6 +1187,12 @@
|
||||
<data name="ViewDialogDailyNoteWebhookUrlTitle" xml:space="preserve">
|
||||
<value>即時便箋 Webhook Url</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>匯入祈願記錄</value>
|
||||
</data>
|
||||
@@ -1271,6 +1289,12 @@
|
||||
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
|
||||
<value>使用米遊社掃描 QR 碼</value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTextHeader" xml:space="preserve">
|
||||
<value>為防止你在無意間啟用,請輸入正在啟用的功能開關的<b>標題名稱</b></value>
|
||||
</data>
|
||||
<data name="ViewDialogReconfirmTitle" xml:space="preserve">
|
||||
<value>你正在啟用一個危險功能</value>
|
||||
</data>
|
||||
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
|
||||
<value>該操作是不可逆,所有用戶登錄狀態會遺失</value>
|
||||
</data>
|
||||
@@ -1292,6 +1316,9 @@
|
||||
<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>
|
||||
@@ -1430,6 +1457,9 @@
|
||||
<data name="ViewModelDailyNoteHoyolabVerificationUnsupported" xml:space="preserve">
|
||||
<value>HoYoLAB 賬號不支持驗證實时便箋</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteModifyTaskFail" xml:space="preserve">
|
||||
<value>修改計劃任務失敗</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRefreshTime30" xml:space="preserve">
|
||||
<value>30 分鐘 | 3.75 樹脂</value>
|
||||
</data>
|
||||
@@ -1445,9 +1475,6 @@
|
||||
<data name="ViewModelDailyNoteRefreshTime8" xml:space="preserve">
|
||||
<value>8 分鐘 | 1 樹脂</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||
<value>注冊計劃任務失敗,請以管理員模式重試</value>
|
||||
</data>
|
||||
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||
<value>正在獲取實時便箋信息,請稍候</value>
|
||||
</data>
|
||||
@@ -1541,6 +1568,9 @@
|
||||
<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>
|
||||
@@ -1554,7 +1584,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>
|
||||
@@ -1574,6 +1604,12 @@
|
||||
<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>
|
||||
@@ -1656,7 +1692,7 @@
|
||||
<value>遊戲公告</value>
|
||||
</data>
|
||||
<data name="ViewPageAnnouncementViewDetails" xml:space="preserve">
|
||||
<value>查看详情</value>
|
||||
<value>檢視詳情</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyArtifactScore" xml:space="preserve">
|
||||
<value>聖遺物評分</value>
|
||||
@@ -1698,7 +1734,7 @@
|
||||
<value>同步角色天賦信息</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecord" xml:space="preserve">
|
||||
<value>從 HoYoLAB - 戰績中同步</value>
|
||||
<value>從米遊社原神戰績同步</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyRefreshFromHoyolabGameRecordDescription" xml:space="preserve">
|
||||
<value>同步角色天賦外的大部分信息</value>
|
||||
@@ -1823,6 +1859,48 @@
|
||||
<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="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>解除 Loopback 限制</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>
|
||||
@@ -2016,7 +2094,7 @@
|
||||
<value>至少需要八個字元</value>
|
||||
</data>
|
||||
<data name="ViewPageHutaoPassportRegisterHeader" xml:space="preserve">
|
||||
<value>註冊</value>
|
||||
<value>建立帳號</value>
|
||||
</data>
|
||||
<data name="ViewPageHutaoPassportResetPasswordHeader" xml:space="preserve">
|
||||
<value>重設密碼</value>
|
||||
@@ -2112,10 +2190,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>
|
||||
@@ -2142,13 +2220,13 @@
|
||||
<value>資源下載</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
|
||||
<value>用戶端</value>
|
||||
<value>完整包</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>預下載</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSelectGamePath" xml:space="preserve">
|
||||
<value>选择游戏路径</value>
|
||||
<value>選擇遊戲路徑</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchAccountAttachUidNull" xml:space="preserve">
|
||||
<value>該用戶尚未綁定即時便箋通知 UID</value>
|
||||
@@ -2163,7 +2241,7 @@
|
||||
<value>檢測</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchAccountHeader" xml:space="preserve">
|
||||
<value>檢測賬號</value>
|
||||
<value>檢測帳號</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchAccountRemoveToolTip" xml:space="preserve">
|
||||
<value>刪除</value>
|
||||
@@ -2172,7 +2250,7 @@
|
||||
<value>重新命名</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchSchemeDescription" xml:space="preserve">
|
||||
<value>切換游戲伺服器(國服/渠道服/國際服)</value>
|
||||
<value>切換遊戲伺服器(陸服/渠道服/國際服)</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchSchemeHeader" xml:space="preserve">
|
||||
<value>伺服器</value>
|
||||
@@ -2192,6 +2270,12 @@
|
||||
<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>
|
||||
@@ -2214,7 +2298,7 @@
|
||||
<value>外觀</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingApperanceLanguageDescription" xml:space="preserve">
|
||||
<value>設定系統語言</value>
|
||||
<value>設定呈現語言</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingApperanceLanguageHeader" xml:space="preserve">
|
||||
<value>語言</value>
|
||||
@@ -2226,7 +2310,7 @@
|
||||
<value>背景材質</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>圖片緩存存放在此</value>
|
||||
<value>圖片暫存存放在此</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderHeader" xml:space="preserve">
|
||||
<value>暫存檔案夾</value>
|
||||
@@ -2238,7 +2322,7 @@
|
||||
<value>創建</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCreateDesktopShortcutDescription" xml:space="preserve">
|
||||
<value>在桌面上創建預設以管理員方式啟動的快捷方式</value>
|
||||
<value>在桌面上創建預設以系統管理員方式啟動的捷徑</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCreateDesktopShortcutHeader" xml:space="preserve">
|
||||
<value>創建快捷方式</value>
|
||||
@@ -2283,13 +2367,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>
|
||||
@@ -2313,7 +2397,7 @@
|
||||
<value>祈願記錄</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingGameHeader" xml:space="preserve">
|
||||
<value>游戲</value>
|
||||
<value>遊戲</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingGeetestCustomUrlAction" xml:space="preserve">
|
||||
<value>配置</value>
|
||||
@@ -2328,10 +2412,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>
|
||||
@@ -2361,7 +2445,7 @@
|
||||
<value>主頁</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoPassportDangerZoneDescription" xml:space="preserve">
|
||||
<value>三思而后行</value>
|
||||
<value>三思而後行</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoPassportDangerZoneHeader" xml:space="preserve">
|
||||
<value>危險操作</value>
|
||||
@@ -2442,10 +2526,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>
|
||||
@@ -2556,7 +2640,7 @@
|
||||
<value>登入失敗,請重新登入</value>
|
||||
</data>
|
||||
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
|
||||
<value>立即登入或註冊</value>
|
||||
<value>立即登入或建立帳號</value>
|
||||
</data>
|
||||
<data name="ViewSettingAllocConsoleDescription" xml:space="preserve">
|
||||
<value>控制胡桃啟動時是否開啟主控台,重新啟動後生效</value>
|
||||
@@ -2564,9 +2648,18 @@
|
||||
<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>
|
||||
@@ -2634,10 +2727,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>
|
||||
@@ -2673,10 +2766,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>
|
||||
@@ -2685,10 +2778,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>
|
||||
@@ -2700,7 +2793,7 @@
|
||||
<value>用戶</value>
|
||||
</data>
|
||||
<data name="ViewWelcomeBase" xml:space="preserve">
|
||||
<value>我們將爲你下載最基本的圖像資源</value>
|
||||
<value>我們將為你下載最基本的圖像資源</value>
|
||||
</data>
|
||||
<data name="ViewWelcomeBody" xml:space="preserve">
|
||||
<value>你可以繼續使用電腦,絲毫不受影響</value>
|
||||
@@ -2747,6 +2840,9 @@
|
||||
<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>
|
||||
@@ -2754,10 +2850,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>
|
||||
@@ -2847,7 +2943,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>
|
||||
@@ -2889,42 +2985,45 @@
|
||||
<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>
|
||||
BIN
src/Snap.Hutao/Snap.Hutao/Resource/TestBackground.jpg
Normal file
BIN
src/Snap.Hutao/Snap.Hutao/Resource/TestBackground.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 MiB |
@@ -60,14 +60,16 @@ internal sealed partial class DailyNoteOptions : DbStoreOptions
|
||||
{
|
||||
if (!scheduleTaskInterop.RegisterForDailyNoteRefresh(SelectedRefreshTime.Value))
|
||||
{
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteRegisterTaskFail);
|
||||
return;
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteModifyTaskFail);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduleTaskInterop.UnregisterForDailyNoteRefresh();
|
||||
if (!scheduleTaskInterop.UnregisterForDailyNoteRefresh())
|
||||
{
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteModifyTaskFail);
|
||||
}
|
||||
}
|
||||
|
||||
OnPropertyChanged();
|
||||
@@ -106,7 +108,7 @@ internal sealed partial class DailyNoteOptions : DbStoreOptions
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteRegisterTaskFail);
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteModifyTaskFail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using System.Collections.Specialized;
|
||||
using System.Web;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.ViewModel.User;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Game.PathAbstraction;
|
||||
using Snap.Hutao.Win32.Graphics.Gdi;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using Windows.Graphics;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static Snap.Hutao.Win32.Gdi32;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Service.Game;
|
||||
|
||||
@@ -82,12 +82,12 @@ internal sealed class LaunchOptions : DbStoreOptions
|
||||
HDC hDC = default;
|
||||
try
|
||||
{
|
||||
hDC = GetDC(HWND.Null);
|
||||
hDC = GetDC(default);
|
||||
fps = GetDeviceCaps(hDC, GET_DEVICE_CAPS_INDEX.VREFRESH);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_ = ReleaseDC(HWND.Null, hDC);
|
||||
_ = ReleaseDC(default, hDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,9 @@ internal sealed class LaunchOptions : DbStoreOptions
|
||||
|
||||
public List<AspectRatio> AspectRatios { get; } =
|
||||
[
|
||||
new(2560, 1600),
|
||||
new(2560, 1440),
|
||||
new(2410, 1080),
|
||||
new(1920, 1080),
|
||||
];
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Progress;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
@@ -124,6 +125,11 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
|
||||
|
||||
private static bool CheckDirectoryPermissions(string folder)
|
||||
{
|
||||
if (LocalSetting.Get(SettingKeys.OverridePackageConvertDirectoryPermissionsRequirement, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Program Files has special permissions limitation.
|
||||
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||
if (folder.StartsWith(programFiles, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user