Update application UI and functionality

This commit is contained in:
2026-07-26 16:20:36 +08:00
parent b9aff58f32
commit 97ea6fb7aa
48 changed files with 2790 additions and 628 deletions
+48
View File
@@ -0,0 +1,48 @@
YMhut Box 软件许可与服务协议
更新日期:2026 年 7 月 25 日
请在安装和使用 YMhut Box 前完整阅读本协议。点击“我已阅读并同意”或继续安装,即表示您已理解并同意本协议的全部内容;如不同意,请退出安装程序。
一、许可范围
1. YMhut Box 授予您一项有限的、非独占的、不可转让的使用许可,用于在您拥有或合法管理的 Windows 设备上安装和使用本软件。
2. 本许可不代表软件、品牌、界面设计或相关服务的所有权发生转移。
3. 未经明确授权,不得利用本软件从事违法活动、破坏系统或网络安全、侵害他人权益,或规避第三方服务的付费、地区及版权限制。
二、安装、更新与卸载
1. 安装程序会检查 Windows 版本、系统架构、目标目录、磁盘空间以及必要运行组件。
2. 当 WebView2 Runtime 或 Microsoft Visual C++ x64 Runtime 缺失时,安装程序可能从微软官方地址下载并安装相应组件,并可能请求管理员权限。
3. 升级或修复安装将尽量保留用户设置和本地数据;卸载前请自行备份重要内容。
三、数据与网络访问
1. 软件设置、缓存、登录凭据和运行日志原则上保存在本机;敏感登录信息按产品实现使用 Windows 系统能力进行保护。
2. 天气、更新、反馈、网络音乐和其他联网功能会访问相应服务提供方。具体可用性、内容和处理规则同时受该服务提供方条款约束。
3. 为诊断故障,软件可能在本机记录必要的错误信息。日志不应被用于存储用户主动输入的密码等敏感内容。
四、第三方组件与服务
1. 软件可能包含或调用微软运行库、硬件监控组件及其他第三方组件。相关组件的权利由其权利人享有,并适用各自的许可或服务条款。
2. 对于跳转至第三方网站、下载地址或服务产生的内容、费用、账户及可用性,应以第三方实际规则为准。
五、功能与风险提示
1. 硬件监控结果受设备、驱动、权限和传感器能力影响,仅供参考。
2. 系统优化、注册表、服务、电源、网络和驱动相关操作可能改变系统行为。请在执行前阅读变更预览并保留可用备份或还原点。
3. 因设备差异、系统策略、第三方服务中断或不可抗力,部分功能可能暂时不可用。
六、责任限制
在法律允许的范围内,YMhut Box 不对因错误配置、未经授权的系统操作、第三方服务变化、网络故障或用户未备份数据造成的间接损失承担责任。本条不排除依法不得限制或排除的责任。
七、协议更新与终止
1. 软件功能、服务方式或合规要求发生变化时,本协议可能更新。重要变更将在软件或发布渠道中提示。
2. 如您违反本协议或利用软件从事违法行为,相关使用许可可以被终止。
3. 协议终止后,您应停止使用并可通过系统卸载功能移除软件。
八、联系与反馈
您可以通过 YMhut Box 内置反馈页面提交功能建议、问题报告或协议相关咨询。
+91 -25
View File
@@ -482,6 +482,11 @@ begin
QueueInstallOutput(Text, True, True);
end;
procedure LogBootstrapEvent(const EventName, Value: string);
begin
Log('YMHUT_EVENT:' + EventName + '|' + Value);
end;
procedure LogCurrentExtractFile();
var
FileName: string;
@@ -718,28 +723,67 @@ begin
Result := FmtMessage(CustomMessage(Key), [Value1, Value2]);
end;
function DownloadAndInstallPrerequisite(const Url, FileName, Arguments, FriendlyName: string; var NeedsRestart: Boolean): Boolean;
function AcquireAndInstallPrerequisite(
const Url, DownloadFileName, BundledFileName, Arguments, FriendlyName: string;
const Bundled: Boolean; var NeedsRestart: Boolean): Boolean;
var
Attempt: Integer;
Downloaded: Boolean;
LastDownloadError: string;
ResultCode: Integer;
ExecutablePath: string;
begin
Result := False;
ExecutablePath := ExpandConstant('{tmp}\' + FileName);
DownloadPage.Clear;
DownloadPage.Add(Url, FileName, '');
if not WizardSilent then
DownloadPage.Show;
try
DownloadPage.Download;
except
if DownloadPage.AbortedByUser then
RaiseException(FormatCustomMessage('DependencyDownloadCancelled', FriendlyName))
else
RaiseException(FormatCustomMessage2('DependencyDownloadFailed', FriendlyName, GetExceptionMessage));
end;
if not WizardSilent then
DownloadPage.Hide;
if Bundled then
begin
LogBootstrapEvent('DEPENDENCY', 'bundled|' + FriendlyName);
ExtractTemporaryFile(BundledFileName);
ExecutablePath := ExpandConstant('{tmp}\' + BundledFileName);
end
else
begin
ExecutablePath := ExpandConstant('{tmp}\' + DownloadFileName);
Downloaded := False;
LastDownloadError := '';
for Attempt := 1 to 3 do
begin
LogBootstrapEvent('DEPENDENCY', 'download|' + FriendlyName);
DownloadPage.Clear;
DownloadPage.Add(Url, DownloadFileName, '');
if not WizardSilent then
DownloadPage.Show;
try
try
DownloadPage.Download;
Downloaded := True;
except
if DownloadPage.AbortedByUser then
RaiseException(FormatCustomMessage('DependencyDownloadCancelled', FriendlyName))
else
LastDownloadError := GetExceptionMessage;
end;
finally
if not WizardSilent then
DownloadPage.Hide;
end;
if Downloaded then
Break;
if Attempt < 3 then
begin
LogBootstrapEvent('DEPENDENCY', 'retry|' + FriendlyName);
Sleep(Attempt * 1500);
end;
end;
if not Downloaded then
RaiseException(FormatCustomMessage2('DependencyDownloadFailed', FriendlyName, LastDownloadError));
end;
if not FileExists(ExecutablePath) then
RaiseException(FormatCustomMessage2('DependencyDownloadFailed', FriendlyName, 'downloaded file is missing'));
LogBootstrapEvent('DEPENDENCY', 'install|' + FriendlyName);
if not Exec(ExecutablePath, Arguments, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
RaiseException(FormatCustomMessage('DependencyStartFailed', FriendlyName));
@@ -749,9 +793,16 @@ begin
if (ResultCode = 3010) or (ResultCode = 1641) then
NeedsRestart := True;
LogBootstrapEvent('DEPENDENCY', 'complete|' + FriendlyName);
Result := True;
end;
procedure SetSetupFailure(var ResultText: string; const MessageText: string);
begin
ResultText := MessageText;
LogBootstrapEvent('FAILURE', MessageText);
end;
procedure CopyIfExists(const Source, TargetDir: string);
begin
if FileExists(Source) then
@@ -900,46 +951,57 @@ end;
function PrepareToInstall(var NeedsRestart: Boolean): string;
begin
AppendInstallOutput('Prepare system prerequisites.');
LogBootstrapEvent('STAGE', 'prerequisites');
Result := '';
#if Int(QAIsolated) == 1
Exit;
#endif
if (ExistingInstallDir <> '') and IsProtectedInstallPath(ExistingInstallDir) and (not IsAdminInstallMode) then
begin
Result := CustomMessage('ProtectedInstallNeedsAdmin');
SetSetupFailure(Result, CustomMessage('ProtectedInstallNeedsAdmin'));
Exit;
end;
if IsProtectedInstallPath(WizardDirValue) and (not IsAdminInstallMode) then
begin
Result := CustomMessage('ProtectedInstallNeedsAdmin');
SetSetupFailure(Result, CustomMessage('ProtectedInstallNeedsAdmin'));
Exit;
end;
try
if not IsWebView2Installed() then
if IsWebView2Installed() then
LogBootstrapEvent('DEPENDENCY', 'ready|' + GetCustomMessageValue('WebView2RuntimeName'))
else
begin
DownloadAndInstallPrerequisite('{#WebView2BootstrapperUrl}', 'MicrosoftEdgeWebView2Setup.exe', '/silent /install', GetCustomMessageValue('WebView2RuntimeName'), NeedsRestart);
AcquireAndInstallPrerequisite(
'{#WebView2BootstrapperUrl}', 'MicrosoftEdgeWebView2Setup.exe',
'MicrosoftEdgeWebView2RuntimeInstallerX64.exe', '/silent /install',
GetCustomMessageValue('WebView2RuntimeName'), BundledWebView2Included = 1, NeedsRestart);
if not WaitForWebView2Installed(60) then
begin
Result := GetCustomMessageValue('WebView2StillMissing');
SetSetupFailure(Result, GetCustomMessageValue('WebView2StillMissing'));
Exit;
end;
end;
if (not IsVCRedistInstalled()) then
if IsVCRedistInstalled() then
LogBootstrapEvent('DEPENDENCY', 'ready|' + GetCustomMessageValue('VCRuntimeName'))
else
begin
DownloadAndInstallPrerequisite('{#VCRedistUrl}', 'vc_redist.x64.exe', '/install /quiet /norestart', GetCustomMessageValue('VCRuntimeName'), NeedsRestart);
AcquireAndInstallPrerequisite(
'{#VCRedistUrl}', 'vc_redist.x64.exe', 'vc_redist.x64.exe',
'/install /quiet /norestart', GetCustomMessageValue('VCRuntimeName'),
BundledVCRedistIncluded = 1, NeedsRestart);
if not WaitForVCRedistInstalled(10) then
begin
Result := GetCustomMessageValue('VCRuntimeStillMissing');
SetSetupFailure(Result, GetCustomMessageValue('VCRuntimeStillMissing'));
Exit;
end;
end;
except
Result := GetExceptionMessage;
SetSetupFailure(Result, GetExceptionMessage);
end;
end;
@@ -954,6 +1016,7 @@ begin
if CurStep = ssInstall then
begin
LastInstallProgressPercent := -1;
LogBootstrapEvent('STAGE', 'files');
AppendInstallOutput(CustomMessage('InstallOutputClean'));
CleanLegacyInstallLayout();
AppendInstallOutput(CustomMessage('InstallOutputExtract'));
@@ -961,6 +1024,7 @@ begin
else if CurStep = ssPostInstall then
begin
FlushInstallOutput();
LogBootstrapEvent('STAGE', 'finalize');
AppendInstallOutput(CustomMessage('InstallOutputPostInstall'));
#if Int(QAIsolated) == 0
MigrateLegacyData();
@@ -980,6 +1044,7 @@ begin
if LastInstallProgressPercent <> 100 then
begin
LastInstallProgressPercent := 100;
LogBootstrapEvent('PROGRESS', '100|' + ExpandConstant(CurrentFileName));
FlushInstallOutput();
end;
Exit;
@@ -991,6 +1056,7 @@ begin
if ProgressPercent <> LastInstallProgressPercent then
begin
LastInstallProgressPercent := ProgressPercent;
LogBootstrapEvent('PROGRESS', IntToStr(ProgressPercent) + '|' + ExpandConstant(CurrentFileName));
FlushInstallOutput();
end;
end;