mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
11 Commits
1.9.0
...
feat/goodb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48ddb4c091 | ||
|
|
ea95f2e2b1 | ||
|
|
93077104b8 | ||
|
|
3ffdc901c7 | ||
|
|
0d66c85744 | ||
|
|
d293149672 | ||
|
|
3784df67a3 | ||
|
|
4aaca4d19f | ||
|
|
e6cf39831d | ||
|
|
24a2a18760 | ||
|
|
d8dce5c062 |
6
.github/ISSUE_TEMPLATE/CHS-bug-report.yml
vendored
6
.github/ISSUE_TEMPLATE/CHS-bug-report.yml
vendored
@@ -22,7 +22,7 @@ body:
|
||||
- label: 我知道文档站的导航栏中有**搜索功能**,且已经搜索过相关关键词
|
||||
required: true
|
||||
|
||||
- label: 我的问题不是[已完成](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E5%AE%8C%E6%88%90)的问题也不是一个别人已发布的**重复的**问题
|
||||
- label: 我的问题不是[已修复](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D)的问题也不是一个别人已发布的**重复的**问题
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
@@ -51,7 +51,7 @@ body:
|
||||
description: |
|
||||
在胡桃工具箱的设置界面,你可以找到并复制你的设备 ID
|
||||
如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题
|
||||
如果你的程序已经无法启动,请下载并运行[此工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
|
||||
如果你的程序已经无法启动,请下载并运行[此PowerShell脚本](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1),它将显示你的设备 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`
|
||||
如果你无法找到该日志,请下载并运行[此PowerShell脚本](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/dump_log_script/dump_log_zh.ps1),它将输出错误日志
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/ENG-bug-report.yml
vendored
6
.github/ISSUE_TEMPLATE/ENG-bug-report.yml
vendored
@@ -22,7 +22,7 @@ body:
|
||||
- label: I and tried **search feature** in Snap Hutao document site, and no associated article
|
||||
required: true
|
||||
|
||||
- label: My issue is not a [finished issue](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E5%AE%8C%E6%88%90), and it's not a duplicated issue
|
||||
- label: My issue is not a [fixed issue](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D), and it's not a duplicated issue
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
@@ -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 [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1), 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 [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/dump_log_script/dump_log_en.ps1), it will dump the error log.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
40
.github/ISSUE_TEMPLATE/MGMT-publish.yml
vendored
40
.github/ISSUE_TEMPLATE/MGMT-publish.yml
vendored
@@ -12,32 +12,50 @@ body:
|
||||
value: |
|
||||
|
||||
## 创建版本
|
||||
|
||||
|
||||
- [ ] 同步一次 [Crowdin](https://crowdin.com/project/snap-hutao) 翻译
|
||||
- [ ] 发布 RC 版本(Optional)
|
||||
- [ ] 合并入主分支
|
||||
- [ ] 整理更新内容,等待翻译
|
||||
- [ ] 打包
|
||||
- [ ] 提交微软商店
|
||||
- [ ] 包含更新日志
|
||||
- [ ] 在 [Snap.Hutao.Docs@next-patch](https://github.com/DGP-Studio/Snap.Hutao.Docs/tree/next-patch) 分支更新文档并直接开 PR
|
||||
- [ ] 更新日志
|
||||
- [ ] 功能文档更新
|
||||
|
||||
|
||||
## 发布版本 [半自动]
|
||||
|
||||
|
||||
- [ ] 在 GitHub 个人设置中更新 [Publish-Automate Beta PAT](https://github.com/settings/tokens?type=beta),有效期需小于预计发版需要天数
|
||||
- [ ] 将更新的 PAT 更新至 Publish-Automate 库的 [Actions Secrets](https://github.com/DGP-Automation/Publish-Automate/settings/secrets/actions) 中
|
||||
- [ ] 将更新的 PAT 更新至 Publish-Automate 库的 [Actions Secrets](https://github.com/DGP-Studio/Publish-Automate/settings/secrets/actions) 中
|
||||
|
||||
***
|
||||
|
||||
- [ ] 主分支合并入 release 分支
|
||||
- [ ] 等待 Release 自动发布
|
||||
- [ ] 检查极狐是否同步完成 Release
|
||||
|
||||
- [ ] 通知用户
|
||||
- [ ] 运行 [Auto Publish Action](https://github.com/DGP-Studio/Publish-Automate/actions/workflows/auto-publish.yml)
|
||||
- [ ] 在 https://store.rg-adguard.net/ 下载新版本安装包
|
||||
- [ ] Store URL: https://apps.microsoft.com/store/detail/snap-hutao/9PH4NXJ2JN52
|
||||
- [ ] 命名格式为 `Snap.Hutao x.x.x.msix`
|
||||
- [ ] Merge 文档 PR
|
||||
- [ ] 发布 Release
|
||||
- [ ] 更新日志格式(以 1.6.2 版本为例)
|
||||
|
||||
```jsx
|
||||
## Update log
|
||||
https://hut.ao/en/statements/update-log.html#_1-6-2
|
||||
|
||||
## 更新日志
|
||||
[此处从文档复制]
|
||||
|
||||
## What's Changed
|
||||
**Full Changelog**: https://github.com/DGP-Studio/Snap.Hutao/compare/1.6.0...1.6.2
|
||||
```
|
||||
|
||||
- [ ] 通知用户
|
||||
- type: checkboxes
|
||||
id: checklist-final
|
||||
attributes:
|
||||
label: Final Check
|
||||
description: Understand what you are doing
|
||||
description: Understand what you are doing
|
||||
options:
|
||||
- label: I understand that I will get banned from repository if I don't have permission to use this template
|
||||
required: true
|
||||
required: true
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
stages:
|
||||
- fetch
|
||||
- release
|
||||
|
||||
Fetch:
|
||||
stage: fetch
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
tags:
|
||||
- us3
|
||||
script:
|
||||
- apt-get update -qy
|
||||
- apt-get install -y curl jq
|
||||
- RELEASE_INFO=$(curl -sSL "https://api.github.com/repos/$CI_PROJECT_PATH/releases/latest")
|
||||
- ASSET_URL=$(echo "$RELEASE_INFO" | jq -r '.assets[] | select(.name | endswith(".msix")) | .browser_download_url')
|
||||
- SHA256SUMS_URL=$(echo "$RELEASE_INFO" | jq -r '.assets[] | select(.name == "SHA256SUMS") | .browser_download_url')
|
||||
- curl -LJO "$ASSET_URL"
|
||||
- curl -LJO "$SHA256SUMS_URL"
|
||||
- FILE_NAME=$(basename "$ASSET_URL")
|
||||
- SHA256SUMS_NAME=$(basename "$SHA256SUMS_URL")
|
||||
- echo "File name at script stage is $FILE_NAME"
|
||||
- echo "SHA256SUMS name at script stage is $SHA256SUMS_NAME"
|
||||
- echo "THIS_FILE_NAME=$FILE_NAME" >> next.env
|
||||
- echo "THIS_SHA256SUMS_NAME=$SHA256SUMS_NAME" >> next.env
|
||||
after_script:
|
||||
- echo "Current Job ID is $CI_JOB_ID"
|
||||
- echo "THIS_JOB_ID=$CI_JOB_ID" >> next.env
|
||||
artifacts:
|
||||
paths:
|
||||
- "*.msix"
|
||||
- "SHA256SUMS"
|
||||
expire_in: 180 days
|
||||
reports:
|
||||
dotenv: next.env
|
||||
|
||||
release:
|
||||
stage: release
|
||||
image: registry.gitlab.com/gitlab-org/release-cli:latest
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
needs:
|
||||
- job: Fetch
|
||||
artifacts: true
|
||||
variables:
|
||||
TAG: '$CI_COMMIT_TAG'
|
||||
script:
|
||||
- echo "Create Release $TAG"
|
||||
- echo "$THIS_JOB_ID"
|
||||
- echo "$THIS_FILE_NAME"
|
||||
release:
|
||||
name: '$TAG'
|
||||
tag_name: '$TAG'
|
||||
ref: '$TAG'
|
||||
description: 'Release $TAG by CI'
|
||||
assets:
|
||||
links:
|
||||
- name: "$THIS_FILE_NAME"
|
||||
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/$THIS_FILE_NAME?inline=false"
|
||||
link_type: package
|
||||
- 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
|
||||
@@ -61,6 +61,7 @@ FileSaveDialog
|
||||
IFileOpenDialog
|
||||
IFileSaveDialog
|
||||
IPersistFile
|
||||
IShellLinkDataList
|
||||
IShellLinkW
|
||||
ShellLink
|
||||
SHELL_LINK_DATA_FLAGS
|
||||
@@ -69,6 +70,7 @@ SHELL_LINK_DATA_FLAGS
|
||||
IMemoryBufferByteAccess
|
||||
|
||||
// Const value
|
||||
E_FAIL
|
||||
INFINITE
|
||||
RPC_E_WRONG_THREAD
|
||||
MAX_PATH
|
||||
|
||||
@@ -31,4 +31,5 @@
|
||||
<x:String x:Key="UI_EmotionIcon250">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon250.png</x:String>
|
||||
<x:String x:Key="UI_EmotionIcon272">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon272.png</x:String>
|
||||
<x:String x:Key="UI_EmotionIcon293">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon293.png</x:String>
|
||||
<x:String x:Key="UI_EmotionIcon445">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon445.png</x:String>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage;
|
||||
@@ -19,7 +18,6 @@ namespace Snap.Hutao.Core.Shell;
|
||||
internal sealed partial class ShellLinkInterop : IShellLinkInterop
|
||||
{
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
public async ValueTask<bool> TryCreateDesktopShoutcutForElevatedLaunchAsync()
|
||||
{
|
||||
@@ -45,12 +43,15 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
|
||||
HRESULT result = CoCreateInstance<ShellLink, IShellLinkW>(null, CLSCTX.CLSCTX_INPROC_SERVER, out IShellLinkW shellLink);
|
||||
Marshal.ThrowExceptionForHR(result);
|
||||
|
||||
shellLink.SetPath(appOptions.PowerShellPath);
|
||||
shellLink.SetArguments($"""
|
||||
-Command "Start-Process shell:AppsFolder\{runtimeOptions.FamilyName}!App -verb runas"
|
||||
""");
|
||||
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_SHOWMINNOACTIVE);
|
||||
shellLink.SetPath($"shell:AppsFolder\\{runtimeOptions.FamilyName}!App");
|
||||
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
|
||||
shellLink.SetIconLocation(targetLogoPath, 0);
|
||||
|
||||
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");
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
internal sealed class Throttler
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, SemaphoreSlim> methodSemaphoreMap = new();
|
||||
|
||||
public ValueTask<SemaphoreSlimToken> ThrottleAsync(CancellationToken token = default, [CallerMemberName] string callerName = default!, [CallerLineNumber] int callerLine = 0)
|
||||
{
|
||||
string key = $"{callerName}L{callerLine}";
|
||||
SemaphoreSlim semaphore = methodSemaphoreMap.GetOrAdd(key, name => new SemaphoreSlim(1));
|
||||
return semaphore.EnterAsync(token);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Windows.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -15,9 +15,7 @@ internal sealed partial class SettingEntry
|
||||
|
||||
public const string GamePathEntries = "GamePathEntries";
|
||||
|
||||
/// <summary>
|
||||
/// PowerShell 路径
|
||||
/// </summary>
|
||||
[Obsolete("不再使用 PowerShell")]
|
||||
public const string PowerShellPath = "PowerShellPath";
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
IgnorableNamespaces="com uap desktop rescap mp">
|
||||
IgnorableNamespaces="com uap desktop desktop6 rescap mp">
|
||||
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutao"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.0.0" />
|
||||
Version="1.9.1.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao</DisplayName>
|
||||
<PublisherDisplayName>DGP Studio</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
@@ -64,5 +66,6 @@
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust"/>
|
||||
<rescap:Capability Name="unvirtualizedResources"/>
|
||||
</Capabilities>
|
||||
</Package>
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
IgnorableNamespaces="com uap desktop rescap mp">
|
||||
IgnorableNamespaces="com uap desktop desktop6 rescap mp">
|
||||
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutaoDev"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.0.0" />
|
||||
Version="1.9.1.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao Dev</DisplayName>
|
||||
<PublisherDisplayName>DGP Studio</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
@@ -64,5 +66,6 @@
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust"/>
|
||||
<rescap:Capability Name="unvirtualizedResources"/>
|
||||
</Capabilities>
|
||||
</Package>
|
||||
|
||||
@@ -186,9 +186,6 @@
|
||||
<data name="FilePickerImportCommit" xml:space="preserve">
|
||||
<value>导入</value>
|
||||
</data>
|
||||
<data name="FilePickerPowerShellCommit" xml:space="preserve">
|
||||
<value>选择 PowerShell</value>
|
||||
</data>
|
||||
<data name="GuideWindowTitle" xml:space="preserve">
|
||||
<value>欢迎使用胡桃</value>
|
||||
</data>
|
||||
@@ -932,9 +929,6 @@
|
||||
<data name="ServiceGameRegisteryInteropLongPathsDisabled" xml:space="preserve">
|
||||
<value>未开启长路径功能,无法设置注册表键值</value>
|
||||
</data>
|
||||
<data name="ServiceGameRegisteryInteropPowershellNotFound" xml:space="preserve">
|
||||
<value>找不到 PowerShell 的安装目录</value>
|
||||
</data>
|
||||
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
|
||||
<value>无法读取游戏配置文件 {0},可能是文件不存在</value>
|
||||
</data>
|
||||
@@ -2144,6 +2138,9 @@
|
||||
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
|
||||
<value>预下载</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSelectGamePath" xml:space="preserve">
|
||||
<value>选择游戏路径</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameSwitchAccountAttachUidNull" xml:space="preserve">
|
||||
<value>该账号尚未绑定实时便笺通知 UID</value>
|
||||
</data>
|
||||
@@ -2432,12 +2429,6 @@
|
||||
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
|
||||
<value>设置游戏路径时,请选择游戏本体(YuanShen.exe 或 GenshinImpact.exe)而不是启动器(launcher.exe)</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetPowerShellDescription" xml:space="preserve">
|
||||
<value>胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
|
||||
<value>PowerShell 路径</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
|
||||
<value>Shell 体验</value>
|
||||
</data>
|
||||
|
||||
@@ -16,42 +16,12 @@ namespace Snap.Hutao.Service;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed partial class AppOptions : DbStoreOptions
|
||||
{
|
||||
private string? powerShellPath;
|
||||
private bool? isEmptyHistoryWishVisible;
|
||||
private BackdropType? backdropType;
|
||||
private CultureInfo? currentCulture;
|
||||
private Region? region;
|
||||
private string? geetestCustomCompositeUrl;
|
||||
|
||||
public string PowerShellPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetOption(ref powerShellPath, SettingEntry.PowerShellPath, GetDefaultPowerShellLocationOrEmpty);
|
||||
|
||||
static string GetDefaultPowerShellLocationOrEmpty()
|
||||
{
|
||||
string? paths = Environment.GetEnvironmentVariable("Path");
|
||||
if (!string.IsNullOrEmpty(paths))
|
||||
{
|
||||
foreach (StringSegment path in new StringTokenizer(paths, [';']))
|
||||
{
|
||||
if (path is { HasValue: true, Length: > 0 })
|
||||
{
|
||||
if (path.Value.Contains("WindowsPowerShell", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Path.Combine(path.Value, "powershell.exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
set => SetOption(ref powerShellPath, SettingEntry.PowerShellPath, value);
|
||||
}
|
||||
|
||||
public bool IsEmptyHistoryWishVisible
|
||||
{
|
||||
get => GetOption(ref isEmptyHistoryWishVisible, SettingEntry.IsEmptyHistoryWishVisible);
|
||||
|
||||
@@ -77,7 +77,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
||||
|
||||
List<DailyNoteEntry> entryList = await dailyNoteDbService.GetDailyNoteEntryIncludeUserListAsync().ConfigureAwait(false);
|
||||
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
|
||||
entries = new(entryList);
|
||||
entries = entryList.ToObservableCollection();
|
||||
}
|
||||
|
||||
return entries;
|
||||
|
||||
@@ -16,7 +16,6 @@ internal sealed partial class GameAccountService : IGameAccountService
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IGameDbService gameDbService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private ObservableCollection<GameAccount>? gameAccounts;
|
||||
|
||||
@@ -90,12 +89,7 @@ internal sealed partial class GameAccountService : IGameAccountService
|
||||
|
||||
public bool SetGameAccount(GameAccount account)
|
||||
{
|
||||
if (string.IsNullOrEmpty(appOptions.PowerShellPath))
|
||||
{
|
||||
ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropPowershellNotFound, default!);
|
||||
}
|
||||
|
||||
return RegistryInterop.Set(account, appOptions.PowerShellPath);
|
||||
return RegistryInterop.Set(account);
|
||||
}
|
||||
|
||||
public void AttachGameAccountToUid(GameAccount gameAccount, string uid)
|
||||
|
||||
@@ -20,48 +20,16 @@ internal static class RegistryInterop
|
||||
private const string GenshinKey = $@"HKEY_CURRENT_USER\{GenshinPath}";
|
||||
private const string SdkChineseKey = "MIHOYOSDK_ADL_PROD_CN_h3123967166";
|
||||
|
||||
/// <summary>
|
||||
/// 设置键值
|
||||
/// 需要支持
|
||||
/// https://learn.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation
|
||||
/// </summary>
|
||||
/// <param name="account">账户</param>
|
||||
/// <param name="powerShellPath">PowerShell 路径</param>
|
||||
/// <returns>账号是否设置</returns>
|
||||
public static bool Set(GameAccount? account, string powerShellPath)
|
||||
public static bool Set(GameAccount? account)
|
||||
{
|
||||
if (account is not null)
|
||||
{
|
||||
// 存回注册表的字节需要 '\0' 结尾
|
||||
Encoding.UTF8.GetByteCount(account.MihoyoSDK);
|
||||
byte[] tempBytes = Encoding.UTF8.GetBytes(account.MihoyoSDK);
|
||||
byte[] target = new byte[tempBytes.Length + 1];
|
||||
tempBytes.CopyTo(target, 0);
|
||||
byte[] target = [.. Encoding.UTF8.GetBytes(account.MihoyoSDK), 0];
|
||||
Registry.SetValue(GenshinKey, SdkChineseKey, target);
|
||||
|
||||
string base64 = Convert.ToBase64String(target);
|
||||
string path = $"HKCU:{GenshinPath}";
|
||||
string command = $"""
|
||||
-Command "$value = [Convert]::FromBase64String('{base64}'); Set-ItemProperty -Path '{path}' -Name '{SdkChineseKey}' -Value $value -Force;"
|
||||
""";
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
Arguments = command,
|
||||
WorkingDirectory = Path.GetDirectoryName(powerShellPath),
|
||||
CreateNoWindow = true,
|
||||
FileName = powerShellPath,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(startInfo)?.WaitForExit();
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
{
|
||||
ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropLongPathsDisabled, ex);
|
||||
}
|
||||
|
||||
if (Get() == account.MihoyoSDK)
|
||||
string? get = Get();
|
||||
if (get == account.MihoyoSDK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -70,10 +38,6 @@ internal static class RegistryInterop
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在注册表中获取账号信息
|
||||
/// </summary>
|
||||
/// <returns>当前注册表中的信息</returns>
|
||||
public static unsafe string? Get()
|
||||
{
|
||||
object? sdk = Registry.GetValue(GenshinKey, SdkChineseKey, Array.Empty<byte>());
|
||||
|
||||
@@ -49,7 +49,7 @@ internal sealed partial class UpdateService : IUpdateService
|
||||
|
||||
progress.Report(new(versionInformation.Version.ToString(), 0, 0));
|
||||
|
||||
if (versionInformation.Sha256 is not { } sha256)
|
||||
if (versionInformation.Sha256 is not { Length: > 0 } sha256)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Snap.Hutao.Service.User;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(IUserCollectionService))]
|
||||
internal sealed partial class UserCollectionService : IUserCollectionService
|
||||
internal sealed partial class UserCollectionService : IUserCollectionService, IDisposable
|
||||
{
|
||||
private readonly ScopedDbCurrent<BindingUser, Model.Entity.User, UserChangedMessage> dbCurrent;
|
||||
private readonly IUserInitializationService userInitializationService;
|
||||
@@ -22,7 +22,7 @@ internal sealed partial class UserCollectionService : IUserCollectionService
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IMessenger messenger;
|
||||
|
||||
private readonly Throttler throttler = new();
|
||||
private readonly SemaphoreSlim throttler = new(1);
|
||||
|
||||
private ObservableCollection<BindingUser>? userCollection;
|
||||
private Dictionary<string, BindingUser>? midUserMap;
|
||||
@@ -38,7 +38,9 @@ internal sealed partial class UserCollectionService : IUserCollectionService
|
||||
|
||||
public async ValueTask<ObservableCollection<BindingUser>> GetUserCollectionAsync()
|
||||
{
|
||||
using (await throttler.ThrottleAsync().ConfigureAwait(false))
|
||||
// Force run in background thread, otherwise will cause reentrance
|
||||
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
|
||||
using (await throttler.EnterAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (userCollection is null)
|
||||
{
|
||||
@@ -131,17 +133,7 @@ internal sealed partial class UserCollectionService : IUserCollectionService
|
||||
return default;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return uidUserGameRoleMap[uid];
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Sequence contains more than one matching element
|
||||
// TODO: return a specialize UserGameRole to indicate error
|
||||
}
|
||||
|
||||
return default;
|
||||
return uidUserGameRoleMap.GetValueOrDefault(uid);
|
||||
}
|
||||
|
||||
public bool TryGetUserByMid(string mid, [NotNullWhen(true)] out BindingUser? user)
|
||||
@@ -186,4 +178,9 @@ internal sealed partial class UserCollectionService : IUserCollectionService
|
||||
ArgumentNullException.ThrowIfNull(newUser.UserInfo);
|
||||
return new(UserOptionResult.Added, newUser.UserInfo.Uid);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throttler.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shccs="using:Snap.Hutao.Control.Collection.Selector"
|
||||
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvg="using:Snap.Hutao.ViewModel.Game"
|
||||
@@ -346,10 +347,20 @@
|
||||
</Grid>
|
||||
<Grid Visibility="{Binding GamePathSelectedAndValid, Converter={StaticResource BoolToVisibilityRevertConverter}}">
|
||||
<StackPanel
|
||||
MaxWidth="600"
|
||||
Margin="128,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="3">
|
||||
<shci:CachedImage
|
||||
Width="120"
|
||||
Height="120"
|
||||
EnableLazyLoading="False"
|
||||
Source="{StaticResource UI_EmotionIcon445}"/>
|
||||
<TextBlock
|
||||
Margin="0,5,0,21"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{shcm:ResourceString Name=ViewPageLaunchGameSelectGamePath}"/>
|
||||
<Border Style="{ThemeResource BorderCardStyle}">
|
||||
<ListView
|
||||
ItemTemplate="{StaticResource GamePathEntryListTemplate}"
|
||||
@@ -364,9 +375,7 @@
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True">
|
||||
<cwc:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock Foreground="{ThemeResource SystemErrorTextColor}" Text="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"/>
|
||||
</StackPanel>
|
||||
<TextBlock Foreground="{ThemeResource SystemErrorTextColor}" Text="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"/>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
</StackPanel>
|
||||
|
||||
@@ -136,17 +136,17 @@
|
||||
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportLicensedDeveloperDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportLicensedDeveloperHeader}"
|
||||
Visibility="{Binding UserOptions.IsLicensedDeveloper, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
<cwc:SettingsCard
|
||||
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerHeader}"
|
||||
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
Visibility="{Binding UserOptions.IsLicensedDeveloper, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button
|
||||
Command="{Binding OpenTestPageCommand}"
|
||||
Content="TEST"
|
||||
Style="{ThemeResource SettingButtonStyle}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerHeader}"
|
||||
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
<cwc:SettingsCard Description="{Binding UserOptions.GachaLogExpireAtSlim}" Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportGachaLogExpiredAtHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
Command="{Binding Passport.OpenRedeemWebsiteCommand}"
|
||||
@@ -308,20 +308,6 @@
|
||||
</cwc:SettingsCard>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingGameHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingSetGamePathAction}"
|
||||
Command="{Binding SetPowerShellPathCommand}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetPowerShellPathHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True">
|
||||
<cwc:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{shcm:ResourceString Name=ViewPageSettingSetPowerShellDescription}"/>
|
||||
<TextBlock Text="{Binding AppOptions.PowerShellPath}"/>
|
||||
</StackPanel>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingDeleteCacheAction}"
|
||||
|
||||
@@ -23,6 +23,7 @@ using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Game;
|
||||
|
||||
@@ -42,6 +43,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly LaunchStatusOptions launchStatusOptions;
|
||||
private readonly IGameLocatorFactory gameLocatorFactory;
|
||||
private readonly ILogger<LaunchGameViewModel> logger;
|
||||
private readonly IProgressFactory progressFactory;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ResourceClient resourceClient;
|
||||
@@ -261,7 +263,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
GamePathEntries = launchOptions.GetGamePathEntries(out GamePathEntry? entry);
|
||||
UpdateSelectedGamePathEntry(entry, false);
|
||||
UpdateSelectedGamePathEntry(entry, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +281,13 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is Win32Exception win32Exception && win32Exception.HResult == HRESULT.E_FAIL)
|
||||
{
|
||||
// User canceled the operation. ignore
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogCritical(ex, "Launch failed");
|
||||
infoBarService.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using System.Collections.ObjectModel;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Game;
|
||||
|
||||
@@ -71,6 +72,12 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is Win32Exception win32Exception && win32Exception.HResult == HRESULT.E_FAIL)
|
||||
{
|
||||
// User canceled the operation. ignore
|
||||
return;
|
||||
}
|
||||
|
||||
infoBarService.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,18 +174,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
await Launcher.LaunchUriAsync(new("ms-windows-store://pdp/?productid=9PH4NXJ2JN52"));
|
||||
}
|
||||
|
||||
[Command("SetPowerShellPathCommand")]
|
||||
private async Task SetPowerShellPathAsync()
|
||||
{
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.PickFile(SH.FilePickerPowerShellCommit, [("PowerShell", "powershell.exe;pwsh.exe")]);
|
||||
|
||||
if (isOk && Path.GetFileNameWithoutExtension(file).EqualsAny(["POWERSHELL", "PWSH"], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
AppOptions.PowerShellPath = file;
|
||||
}
|
||||
}
|
||||
|
||||
[Command("DeleteGameWebCacheCommand")]
|
||||
private void DeleteGameWebCache()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user