3 Commits

13 changed files with 87 additions and 23 deletions

View File

@@ -4,5 +4,8 @@ This file contains the declaration of all the localizable strings.
<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
<String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." /> <String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." />
<String Id="MainAppTitle" Value="Snap.Hutao" />
<String Id="DesktopShortcutTitle" Value="Desktop Shortcut" />
<String Id="StartMenuShortcutTitle" Value="Start Menu Shortcut" />
</WixLocalization> </WixLocalization>

View File

@@ -1,21 +1,32 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
<Package <Package
Name="Snap.Hutao" Name="Snap.Hutao"
Manufacturer="Millennium Science Technology R-D Inst" Manufacturer="Millennium Science Technology R-D Inst"
Version="1.18.2.0" Version="1.18.3.0"
UpgradeCode="121203be-60cb-408f-92cc-7080f6598e68" UpgradeCode="121203be-60cb-408f-92cc-7080f6598e68"
Language="2052"
Scope="perMachine"> Scope="perMachine">
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> <Property Id="ApplicationFolderName" Value="Snap.Hutao" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
<MediaTemplate EmbedCab="yes" /> <MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="Snap.Hutao" Level="1"> <ui:WixUI Id="WixUI_InstallDir" InstallDirectory="INSTALLFOLDER" />
<ComponentGroupRef Id="MainAppComponents" />
<!-- 快捷方式组件 --> <Feature Id="MainApp" Title="!(loc.MainAppTitle)" Level="1">
<ComponentRef Id="ApplicationShortcut" /> <ComponentGroupRef Id="MainAppComponents" />
</Feature>
<Feature Id="DesktopShortcutFeature" Title="!(loc.DesktopShortcutTitle)" Level="1">
<ComponentRef Id="DesktopShortcut" /> <ComponentRef Id="DesktopShortcut" />
</Feature> </Feature>
<Feature Id="StartMenuShortcutFeature" Title="!(loc.StartMenuShortcutTitle)" Level="1">
<ComponentRef Id="ApplicationShortcut" />
</Feature>
</Package> </Package>
<!-- 安装目录 --> <!-- 安装目录 -->

View File

@@ -0,0 +1,11 @@
<!--
This file contains the declaration of all the localizable strings.
-->
<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="zh-CN">
<String Id="DowngradeError" Value="已安装更新版本的 [ProductName]。" />
<String Id="MainAppTitle" Value="Snap.Hutao" />
<String Id="DesktopShortcutTitle" Value="桌面快捷方式" />
<String Id="StartMenuShortcutTitle" Value="开始菜单快捷方式" />
</WixLocalization>

View File

@@ -4,6 +4,8 @@
<Platform>x64</Platform> <Platform>x64</Platform>
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework> <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<DefaultCulture>zh-CN</DefaultCulture>
<Cultures>zh-CN;en-US</Cultures>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -19,6 +21,13 @@
<SuppressRootDirectory>true</SuppressRootDirectory> <SuppressRootDirectory>true</SuppressRootDirectory>
</HarvestDirectory> </HarvestDirectory>
<PackageReference Include="WixToolset.Heat" Version="4.0.1" /> <PackageReference Include="WixToolset.Heat" Version="6.0.2" />
<PackageReference Include="WixToolset.UI.wixext" Version="6.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<WixLocalization Include="Package.zh-cn.wxl" />
<WixLocalization Include="Package.en-us.wxl" />
</ItemGroup>
</Project> </Project>

View File

@@ -33,6 +33,8 @@ internal static class HutaoRuntime
public static WebView2Version WebView2Version { get; } = InitializeWebView2(); public static WebView2Version WebView2Version { get; } = InitializeWebView2();
public static string WebView2UserDataDirectory { get; } = InitializeWebView2UserDataDirectory();
// ⚠️ 延迟初始化以避免循环依赖 // ⚠️ 延迟初始化以避免循环依赖
private static readonly Lazy<bool> LazyIsProcessElevated = new(GetIsProcessElevated); private static readonly Lazy<bool> LazyIsProcessElevated = new(GetIsProcessElevated);
@@ -144,6 +146,13 @@ internal static class HutaoRuntime
return cacheDir; return cacheDir;
} }
private static string InitializeWebView2UserDataDirectory()
{
string directory = Path.Combine(LocalCacheDirectory, "WebView2");
Directory.CreateDirectory(directory);
return directory;
}
private static bool CheckAppNotificationEnabled() private static bool CheckAppNotificationEnabled()
{ {
try try
@@ -226,4 +235,4 @@ internal static class HutaoRuntime
return new(string.Empty, SH.CoreWebView2HelperVersionUndetected, false); return new(string.Empty, SH.CoreWebView2HelperVersionUndetected, false);
} }
} }
} }

View File

@@ -13,7 +13,7 @@
<Identity <Identity
Name="60568DGPStudio.SnapHutao" Name="60568DGPStudio.SnapHutao"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52" Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.18.1.0" /> Version="1.18.3.0" />
<Properties> <Properties>
<DisplayName>Snap Hutao</DisplayName> <DisplayName>Snap Hutao</DisplayName>

View File

@@ -21,6 +21,8 @@ internal abstract class AbstractLaunchExecutionInvoker
private bool invoked; private bool invoked;
protected ImmutableArray<ILaunchExecutionHandler> Handlers { get; init; } protected ImmutableArray<ILaunchExecutionHandler> Handlers { get; init; }
protected virtual bool ShouldWaitForProcessExit { get => true; }
protected virtual bool ShouldSpinWaitGameExitAfterInvoke { get => true; }
public static bool Invoking() public static bool Invoking()
{ {
@@ -40,7 +42,7 @@ internal abstract class AbstractLaunchExecutionInvoker
finally finally
{ {
Invokers.TryRemove(this, out _); Invokers.TryRemove(this, out _);
if (!Invoking()) if (!Invoking() && ShouldSpinWaitGameExitAfterInvoke)
{ {
await GameLifeCycle.SpinWaitGameExitAsync(taskContext).ConfigureAwait(false); await GameLifeCycle.SpinWaitGameExitAsync(taskContext).ConfigureAwait(false);
} }
@@ -132,7 +134,7 @@ internal abstract class AbstractLaunchExecutionInvoker
} }
// 只有在没有启用Island且进程存在时才等待退出 // 只有在没有启用Island且进程存在时才等待退出
if (process is { IsRunning: true }) if (ShouldWaitForProcessExit && process is { IsRunning: true })
{ {
progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit)); progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit));
try try
@@ -148,7 +150,7 @@ internal abstract class AbstractLaunchExecutionInvoker
return; return;
} }
} }
else if (beforeContext.LaunchOptions.IsIslandEnabled.Value) else if (ShouldWaitForProcessExit && beforeContext.LaunchOptions.IsIslandEnabled.Value)
{ {
progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit)); progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit));
await taskContext.SwitchToBackgroundAsync(); await taskContext.SwitchToBackgroundAsync();
@@ -170,4 +172,4 @@ internal abstract class AbstractLaunchExecutionInvoker
} }
} }
} }
} }

View File

@@ -9,6 +9,9 @@ namespace Snap.Hutao.Service.Game.Launching.Invoker;
internal sealed class ConvertOnlyLaunchExecutionInvoker : AbstractLaunchExecutionInvoker internal sealed class ConvertOnlyLaunchExecutionInvoker : AbstractLaunchExecutionInvoker
{ {
protected override bool ShouldWaitForProcessExit { get => false; }
protected override bool ShouldSpinWaitGameExitAfterInvoke { get => false; }
public ConvertOnlyLaunchExecutionInvoker() public ConvertOnlyLaunchExecutionInvoker()
{ {
Handlers = Handlers =
@@ -24,4 +27,4 @@ internal sealed class ConvertOnlyLaunchExecutionInvoker : AbstractLaunchExecutio
// Since this invoker is only for conversion, we do not actually need the process. // Since this invoker is only for conversion, we do not actually need the process.
return default; return default;
} }
} }

View File

@@ -11,7 +11,7 @@
<UseWinUI>true</UseWinUI> <UseWinUI>true</UseWinUI>
<UseWPF>False</UseWPF> <UseWPF>False</UseWPF>
<!-- 配置版本号 --> <!-- 配置版本号 -->
<Version>1.18.2.0</Version> <Version>1.18.3.0</Version>
<UseWindowsForms>False</UseWindowsForms> <UseWindowsForms>False</UseWindowsForms>
<ImplicitUsings>False</ImplicitUsings> <ImplicitUsings>False</ImplicitUsings>

View File

@@ -20,6 +20,8 @@ internal partial class ScopedPage : Page
protected ScopedPage() protected ScopedPage()
{ {
// Allow a small set of recent pages to be cached to reduce navigation stutter.
NavigationCacheMode = NavigationCacheMode.Enabled;
// Events/Override Methods order // Events/Override Methods order
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Page Navigation methods: // Page Navigation methods:
@@ -103,6 +105,13 @@ internal partial class ScopedPage : Page
private void OnUnloaded(object sender, RoutedEventArgs e) private void OnUnloaded(object sender, RoutedEventArgs e)
{ {
// When navigation cache is enabled, the page instance is reused.
// Do not tear down DataContext/scope here to avoid invalid state on return.
if (NavigationCacheMode != NavigationCacheMode.Disabled)
{
return;
}
// Cancel all tasks executed by the view model // Cancel all tasks executed by the view model
viewCts.Cancel(); viewCts.Cancel();
@@ -140,4 +149,4 @@ internal partial class ScopedPage : Page
Unloaded -= OnUnloaded; Unloaded -= OnUnloaded;
} }
} }

View File

@@ -264,10 +264,13 @@
<shuxv:UserView x:Name="UserView"/> <shuxv:UserView x:Name="UserView"/>
</NavigationView.PaneFooter> </NavigationView.PaneFooter>
<Frame x:Name="ContentFrame" ContentTransitions="{StaticResource NavigationThemeTransitions}"/> <Frame
x:Name="ContentFrame"
CacheSize="5"
ContentTransitions="{StaticResource NavigationThemeTransitions}"/>
</NavigationView> </NavigationView>
</Grid> </Grid>
<shuxv:InfoBarView Margin="0,44,0,0" VerticalAlignment="Stretch"/> <shuxv:InfoBarView Margin="0,44,0,0" VerticalAlignment="Stretch"/>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -6,6 +6,7 @@ using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Input;
using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Logging; using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Setting; using Snap.Hutao.Core.Setting;
using Snap.Hutao.UI.Input.LowLevel; using Snap.Hutao.UI.Input.LowLevel;
@@ -337,7 +338,8 @@ internal sealed partial class CompactWebView2Window : Microsoft.UI.Xaml.Window,
{ {
AdditionalBrowserArguments = "--do-not-de-elevate --autoplay-policy=no-user-gesture-required", AdditionalBrowserArguments = "--do-not-de-elevate --autoplay-policy=no-user-gesture-required",
}; };
CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, null, options); string userDataFolder = HutaoRuntime.WebView2UserDataDirectory;
CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, userDataFolder, options);
await WebView.EnsureCoreWebView2Async(environment); await WebView.EnsureCoreWebView2Async(environment);
} }
catch (SEHException ex) catch (SEHException ex)
@@ -430,4 +432,4 @@ internal sealed partial class CompactWebView2Window : Microsoft.UI.Xaml.Window,
RefreshButton.Command = RefreshCommand; RefreshButton.Command = RefreshCommand;
ProgressRing.Visibility = Visibility.Collapsed; ProgressRing.Visibility = Visibility.Collapsed;
} }
} }

View File

@@ -5,6 +5,7 @@ using Microsoft.UI;
using Microsoft.UI.Windowing; using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Logging; using Snap.Hutao.Core.Logging;
using Snap.Hutao.UI.Windowing; using Snap.Hutao.UI.Windowing;
using Snap.Hutao.UI.Windowing.Abstraction; using Snap.Hutao.UI.Windowing.Abstraction;
@@ -154,7 +155,8 @@ internal sealed partial class WebView2Window : Microsoft.UI.Xaml.Window,
{ {
AdditionalBrowserArguments = "--do-not-de-elevate", AdditionalBrowserArguments = "--do-not-de-elevate",
}; };
CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, null, options); string userDataFolder = HutaoRuntime.WebView2UserDataDirectory;
CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, userDataFolder, options);
await WebView.EnsureCoreWebView2Async(environment); await WebView.EnsureCoreWebView2Async(environment);
} }
catch (SEHException) catch (SEHException)
@@ -213,4 +215,4 @@ internal sealed partial class WebView2Window : Microsoft.UI.Xaml.Window,
{ {
contentProvider.ActualTheme = sender.ActualTheme; contentProvider.ActualTheme = sender.ActualTheme;
} }
} }