Files
SilverMetal/windows/welcome/src/SilverOS.Welcome.App/MainPage.xaml.cs
sysadmin 30a168e853
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m46s
perf(welcome): cut first-boot cold-start + add loading affordance
The Welcome wizard showed nothing until WebView2 cold-started and Blazor
booted, so the whole startup cost presented as a blank window long enough
that operators thought first boot had failed.

- Native MAUI splash overlay (renders in the first frame, no WebView2/JIT
  dependency) + a visually identical in-page splash inside #app, so the
  native -> webview -> Blazor handoff reads as one continuous loading
  screen. Fades out on first successful WV2 NavigationCompleted.
- PublishReadyToRun=true (publish-only) to remove first-run JIT on the
  one-shot cold-disk path. R2R header verified present after publish.
- Fixed-version WebView2 runtime baked offline next to the exe (build.ps1
  stages it, app points WEBVIEW2_BROWSER_EXECUTABLE_FOLDER at it). Removes
  the Evergreen registry probe and the LTSC "no WebView2 at all" risk flagged
  in welcome-app-spec.md; air-gap friendly. Absent => falls back to Evergreen.
- De-flash launch: drop the `cmd /c` wrapper and add -WindowStyle Hidden in
  autounattend FirstLogonCommands (kills the console flash + one process).

Verified: Release build clean, win-x64 self-contained publish succeeds with
R2R confirmed, 38/38 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:06:02 +01:00

63 lines
1.7 KiB
C#

using Microsoft.AspNetCore.Components.WebView;
namespace SilverOS.Welcome.App;
public partial class MainPage : ContentPage
{
bool _splashDismissed;
public MainPage()
{
InitializeComponent();
Diag.Log("MainPage ctor");
}
// Fires once the platform WebView2 is created. If this never appears in the log,
// WebView2 environment creation failed (the real cause of a blank wizard).
void OnBlazorInitialized(object? sender, BlazorWebViewInitializedEventArgs e)
{
Diag.Log("BlazorWebViewInitialized");
#if WINDOWS
try
{
var wv = e.WebView; // Microsoft.UI.Xaml.Controls.WebView2
wv.NavigationCompleted += (a, b) =>
{
Diag.Log($"WV2 NavigationCompleted ok={b.IsSuccess} status={b.WebErrorStatus}");
// First completed navigation = the WebView has content on screen.
// Drop the native splash so the (visually identical) in-page splash
// carries through Blazor's final boot without a flash of blank.
if (b.IsSuccess) DismissSplash();
};
if (wv.CoreWebView2 is not null)
wv.CoreWebView2.ProcessFailed += (a, b) =>
Diag.Log("WV2 ProcessFailed: " + b.ProcessFailedKind);
}
catch (Exception ex) { Diag.Log("WV2 hook failed: " + ex.Message); }
#endif
}
// Fade the native splash out once, then collapse it so it never intercepts input.
void DismissSplash()
{
if (_splashDismissed) return;
_splashDismissed = true;
MainThread.BeginInvokeOnMainThread(async () =>
{
try
{
await SplashOverlay.FadeTo(0, 250, Easing.CubicOut);
}
catch { /* fade is cosmetic — never block on it */ }
finally
{
SplashOverlay.IsVisible = false;
SplashOverlay.InputTransparent = true;
}
});
}
void OnUrlLoading(object? sender, UrlLoadingEventArgs e)
=> Diag.Log("UrlLoading: " + e.Url);
}