Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
using System.Globalization ;
2026-04-21 20:59:52 +08:00
using System.Text.Json ;
using LanMountainDesktop.Launcher.Models ;
using LanMountainDesktop.Shared.Contracts.Launcher ;
namespace LanMountainDesktop.Launcher.Services ;
internal sealed class DeploymentLocator
{
private readonly string _appRoot ;
public DeploymentLocator ( string appRoot )
{
_appRoot = appRoot ;
}
public string GetAppRoot ( ) = > _appRoot ;
public string? FindCurrentDeploymentDirectory ( )
{
Console . WriteLine ( "[DeploymentLocator] Searching for deployment directories (ClassIsland style)..." ) ;
if ( ! Directory . Exists ( _appRoot ) )
{
Console . WriteLine ( "[DeploymentLocator] App root directory does not exist" ) ;
return null ;
}
var executable = OperatingSystem . IsWindows ( ) ? "LanMountainDesktop.exe" : "LanMountainDesktop" ;
try
{
var candidates = Directory . GetDirectories ( _appRoot , "app-*" , SearchOption . TopDirectoryOnly ) ;
Console . WriteLine ( $"[DeploymentLocator] Found {candidates.Length} app-* directories" ) ;
var validInstallations = candidates
. Where ( path = >
{
var hasDestroy = File . Exists ( Path . Combine ( path , ".destroy" ) ) ;
var hasPartial = File . Exists ( Path . Combine ( path , ".partial" ) ) ;
var hasExe = File . Exists ( Path . Combine ( path , executable ) ) ;
var hasCurrent = File . Exists ( Path . Combine ( path , ".current" ) ) ;
var version = ParseVersionFromDirectory ( path ) ;
Console . WriteLine ( $"[DeploymentLocator] Candidate: {Path.GetFileName(path)} | " +
$"Version={version} | " +
$"Current={hasCurrent} | " +
$"Destroy={hasDestroy} | " +
$"Partial={hasPartial} | " +
$"HasExe={hasExe}" ) ;
return ! hasDestroy & & ! hasPartial & & hasExe ;
} )
. Select ( path = > new
{
Path = path ,
Version = ParseVersionFromDirectory ( path ) ,
HasCurrentMarker = File . Exists ( Path . Combine ( path , ".current" ) )
} )
2026-04-23 00:27:01 +08:00
. OrderBy ( x = > x . HasCurrentMarker ? 0 : 1 ) // .current 鏍囪鐨勬帓鍓嶉潰
. ThenByDescending ( x = > x . Version ) // 鐒跺悗鎸夌増鏈彿闄嶅簭
2026-04-21 20:59:52 +08:00
. ToList ( ) ;
if ( validInstallations . Count = = 0 )
{
Console . WriteLine ( "[DeploymentLocator] No valid deployment directories found" ) ;
return null ;
}
var best = validInstallations [ 0 ] ;
Console . WriteLine ( $"[DeploymentLocator] Selected: {Path.GetFileName(best.Path)} (current={best.HasCurrentMarker}, version={best.Version})" ) ;
return best . Path ;
}
catch ( Exception ex )
{
Console . Error . WriteLine ( $"[DeploymentLocator] Error searching for deployments: {ex}" ) ;
return null ;
}
}
2026-04-22 07:31:54 +08:00
public HostResolutionResult ResolveHostExecutable ( CommandContext context )
2026-04-21 20:59:52 +08:00
{
2026-04-22 07:31:54 +08:00
ArgumentNullException . ThrowIfNull ( context ) ;
var executable = OperatingSystem . IsWindows ( ) ? "LanMountainDesktop.exe" : "LanMountainDesktop" ;
var searchedPaths = new List < string > ( ) ;
var explicitAppRoot = context . ExplicitAppRoot ;
var devModeConfigIgnored = ! context . IsDebugMode & & Views . ErrorWindow . CheckDevModeEnabled ( ) ;
string? resolvedPath ;
string? source ;
if ( ! string . IsNullOrWhiteSpace ( explicitAppRoot ) )
{
var explicitRoot = Path . GetFullPath ( explicitAppRoot ) ;
resolvedPath = TryResolveExplicitAppRoot ( explicitRoot , executable , searchedPaths , out source ) ;
}
else
{
resolvedPath = TryResolvePublishedOrPortableHost ( executable , searchedPaths , out source ) ;
}
if ( resolvedPath is null & & context . IsDebugMode )
2026-04-21 20:59:52 +08:00
{
2026-04-22 07:31:54 +08:00
resolvedPath = TryResolveDebugHost ( executable , searchedPaths , out source ) ;
}
if ( resolvedPath is null )
{
resolvedPath = ResolveHostExecutablePathLegacy ( ) ;
if ( ! string . IsNullOrWhiteSpace ( resolvedPath ) )
2026-04-21 20:59:52 +08:00
{
2026-04-22 07:31:54 +08:00
searchedPaths . Add ( Path . GetFullPath ( resolvedPath ) ) ;
source = "legacy_fallback" ;
2026-04-21 20:59:52 +08:00
}
2026-04-22 07:31:54 +08:00
}
return new HostResolutionResult
{
Success = ! string . IsNullOrWhiteSpace ( resolvedPath ) ,
ResolvedHostPath = resolvedPath ,
ResolutionSource = source ,
AppRoot = _appRoot ,
ExplicitAppRoot = explicitAppRoot ,
DevModeConfigIgnored = devModeConfigIgnored ,
SearchedPaths = searchedPaths
. Where ( path = > ! string . IsNullOrWhiteSpace ( path ) )
. Distinct ( StringComparer . OrdinalIgnoreCase )
. ToList ( )
2026-04-21 20:59:52 +08:00
} ;
2026-04-22 07:31:54 +08:00
}
2026-04-21 20:59:52 +08:00
2026-04-22 07:31:54 +08:00
public string? ResolveHostExecutablePath ( )
{
return ResolveHostExecutablePathLegacy ( ) ;
}
private string? TryResolveExplicitAppRoot (
string explicitRoot ,
string executable ,
List < string > searchedPaths ,
out string? source )
{
var directPath = Path . Combine ( explicitRoot , executable ) ;
searchedPaths . Add ( directPath ) ;
if ( File . Exists ( directPath ) )
2026-04-21 20:59:52 +08:00
{
2026-04-22 07:31:54 +08:00
source = "explicit_app_root_direct" ;
return directPath ;
2026-04-21 20:59:52 +08:00
}
2026-04-22 07:31:54 +08:00
var deployment = FindBestDeploymentHost ( explicitRoot , executable , searchedPaths ) ;
if ( deployment is not null )
{
source = "explicit_app_root_deployment" ;
return deployment ;
}
source = null ;
return null ;
}
private string? TryResolvePublishedOrPortableHost (
string executable ,
List < string > searchedPaths ,
out string? source )
{
var deployment = FindBestDeploymentHost ( _appRoot , executable , searchedPaths ) ;
if ( deployment is not null )
{
source = "published_deployment" ;
return deployment ;
}
var portableCandidates = new [ ]
{
Path . Combine ( _appRoot , executable ) ,
Path . Combine ( AppContext . BaseDirectory , executable )
} ;
foreach ( var candidate in portableCandidates
. Select ( Path . GetFullPath )
. Distinct ( StringComparer . OrdinalIgnoreCase ) )
{
searchedPaths . Add ( candidate ) ;
if ( File . Exists ( candidate ) )
{
source = "portable_host" ;
return candidate ;
}
}
source = null ;
return null ;
}
private string? TryResolveDebugHost (
string executable ,
List < string > searchedPaths ,
out string? source )
{
if ( Views . ErrorWindow . CheckDevModeEnabled ( ) )
{
var savedCustomPath = Views . ErrorWindow . GetSavedCustomHostPath ( ) ;
if ( ! string . IsNullOrWhiteSpace ( savedCustomPath ) )
{
2026-04-23 19:04:39 +08:00
if ( TryNormalizeSavedDebugPath ( savedCustomPath , out var fullSavedPath ) )
2026-04-22 07:31:54 +08:00
{
2026-04-23 19:04:39 +08:00
searchedPaths . Add ( fullSavedPath ) ;
if ( File . Exists ( fullSavedPath ) )
{
source = "debug_saved_custom_path" ;
return fullSavedPath ;
}
Logger . Warn ( $"Saved launcher debug host path is invalid; falling back to development paths. Path='{fullSavedPath}'." ) ;
2026-04-22 07:31:54 +08:00
}
}
}
foreach ( var devPath in GetDevelopmentPaths ( executable ) )
{
var fullPath = Path . GetFullPath ( devPath ) ;
searchedPaths . Add ( fullPath ) ;
if ( File . Exists ( fullPath ) )
{
source = "debug_build_output" ;
return fullPath ;
}
}
source = null ;
return null ;
}
2026-04-23 19:04:39 +08:00
private static bool TryNormalizeSavedDebugPath ( string savedPath , out string fullSavedPath )
{
try
{
fullSavedPath = Path . GetFullPath ( savedPath ) ;
return true ;
}
catch ( Exception ex )
{
fullSavedPath = string . Empty ;
Logger . Warn ( $"Saved launcher debug host path is invalid and cannot be normalized; falling back to development paths. Path='{savedPath}'; Error='{ex.Message}'." ) ;
return false ;
}
}
2026-04-22 07:31:54 +08:00
private static string? FindBestDeploymentHost (
string root ,
string executable ,
List < string > searchedPaths )
{
if ( ! Directory . Exists ( root ) )
{
searchedPaths . Add ( Path . Combine ( root , "app-*" , executable ) ) ;
return null ;
}
var appDirs = Directory . GetDirectories ( root , "app-*" , SearchOption . TopDirectoryOnly )
. Where ( path = > ! File . Exists ( Path . Combine ( path , ".destroy" ) ) )
. Where ( path = > ! File . Exists ( Path . Combine ( path , ".partial" ) ) )
. Select ( path = > new
{
Path = path ,
HostPath = Path . Combine ( path , executable ) ,
HasCurrent = File . Exists ( Path . Combine ( path , ".current" ) ) ,
Version = ParseVersionFromDirectory ( path )
} )
. OrderByDescending ( item = > item . HasCurrent )
. ThenByDescending ( item = > item . Version )
. ToList ( ) ;
foreach ( var candidate in appDirs )
{
searchedPaths . Add ( candidate . HostPath ) ;
if ( File . Exists ( candidate . HostPath ) )
{
return candidate . HostPath ;
}
}
if ( appDirs . Count = = 0 )
{
searchedPaths . Add ( Path . Combine ( root , "app-*" , executable ) ) ;
}
return null ;
2026-04-21 20:59:52 +08:00
}
private string? ResolveHostExecutablePathLegacy ( )
{
var executable = OperatingSystem . IsWindows ( ) ? "LanMountainDesktop.exe" : "LanMountainDesktop" ;
2026-04-23 00:27:01 +08:00
// 1. 棣栧厛鏌ユ壘 app-{version} 鐩綍锛堢敓浜х幆澧冿級
2026-04-21 20:59:52 +08:00
var currentDeployment = FindCurrentDeploymentDirectory ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currentDeployment ) )
{
var inDeployment = Path . Combine ( currentDeployment , executable ) ;
if ( File . Exists ( inDeployment ) )
{
return inDeployment ;
}
}
var inRoot = Path . Combine ( _appRoot , executable ) ;
if ( File . Exists ( inRoot ) )
{
return inRoot ;
}
var parent = Path . GetFullPath ( Path . Combine ( _appRoot , ".." ) ) ;
var inParent = Path . Combine ( parent , executable ) ;
if ( File . Exists ( inParent ) )
{
return inParent ;
}
2026-04-23 00:27:01 +08:00
// 4. 寮€鍙戞ā寮忥細濡傛灉鍚敤浜嗗紑鍙戞ā寮忥紝浼樺厛浣跨敤淇濆瓨鐨勮嚜瀹氫箟璺緞
2026-04-21 20:59:52 +08:00
if ( Views . ErrorWindow . CheckDevModeEnabled ( ) )
{
var savedCustomPath = Views . ErrorWindow . GetSavedCustomHostPath ( ) ;
2026-04-23 19:04:39 +08:00
if ( ! string . IsNullOrWhiteSpace ( savedCustomPath ) )
2026-04-21 20:59:52 +08:00
{
2026-04-23 19:04:39 +08:00
if ( TryNormalizeSavedDebugPath ( savedCustomPath , out var fullSavedPath ) & &
File . Exists ( fullSavedPath ) )
{
return fullSavedPath ;
}
else if ( ! string . IsNullOrWhiteSpace ( fullSavedPath ) )
{
Logger . Warn ( $"Saved launcher debug host path is invalid; falling back to development paths. Path='{fullSavedPath}'." ) ;
}
2026-04-21 20:59:52 +08:00
}
var devPath = ScanDevelopmentPaths ( executable ) ;
if ( ! string . IsNullOrWhiteSpace ( devPath ) )
{
return devPath ;
}
}
2026-04-23 00:27:01 +08:00
// 5. 寮€鍙戞ā寮忥細鏌ユ壘涓荤▼搴忛」鐩殑杈撳嚭鐩綍
2026-04-21 20:59:52 +08:00
var devPaths = GetDevelopmentPaths ( executable ) ;
foreach ( var devPath in devPaths )
{
if ( File . Exists ( devPath ) )
{
return devPath ;
}
}
return null ;
}
/// <summary>
2026-04-23 00:27:01 +08:00
/// 鎵弿寮€鍙戣矾寰勶紙寮€鍙戞ā寮忥級
2026-04-21 20:59:52 +08:00
/// </summary>
private static string? ScanDevelopmentPaths ( string executable )
{
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
var solutionRoot = Path . GetFullPath ( Path . Combine ( AppContext . BaseDirectory , ".." , ".." , ".." , ".." ) ) ;
2026-04-21 20:59:52 +08:00
var possiblePaths = new [ ]
{
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
// 标准开发路径:解决方案根目录下的 LanMountainDesktop 项目
Path . Combine ( solutionRoot , "LanMountainDesktop" , "bin" , "Debug" , "net10.0" , executable ) ,
Path . Combine ( solutionRoot , "LanMountainDesktop" , "bin" , "Release" , "net10.0" , executable ) ,
// 向后兼容
2026-04-21 20:59:52 +08:00
Path . Combine ( AppContext . BaseDirectory , ".." , ".." , "LanMountainDesktop" , "bin" , "Debug" , "net10.0" , executable ) ,
Path . Combine ( AppContext . BaseDirectory , ".." , ".." , "LanMountainDesktop" , "bin" , "Release" , "net10.0" , executable ) ,
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
// dev-test 目录
Path . Combine ( solutionRoot , "dev-test" , "app-1.0.0-dev" , executable ) ,
2026-04-21 20:59:52 +08:00
} ;
foreach ( var path in possiblePaths . Select ( Path . GetFullPath ) . Distinct ( ) )
{
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
Logger . Info ( $"Scanning development path: {path}" ) ;
2026-04-21 20:59:52 +08:00
if ( File . Exists ( path ) )
{
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
Logger . Info ( $"Found host at: {path}" ) ;
2026-04-21 20:59:52 +08:00
return path ;
}
}
return null ;
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
}
2026-04-21 20:59:52 +08:00
/// <summary>
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
/// 鑾峰彇寮€鍙戞ā寮忥細鏌ユ壘涓荤▼搴忚経
/// </summary>
2026-04-21 20:59:52 +08:00
private static IEnumerable < string > GetDevelopmentPaths ( string executable )
{
var launcherDir = AppContext . BaseDirectory ;
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
// 计算解决方案根目录:从 LanMountainDesktop.Launcher\bin\Debug\net10.0\ 向上4级
var solutionRoot = Path . GetFullPath ( Path . Combine ( launcherDir , ".." , ".." , ".." , ".." ) ) ;
2026-04-21 20:59:52 +08:00
var possiblePaths = new [ ]
{
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
// 标准开发路径:解决方案根目录下的 LanMountainDesktop 项目
Path . Combine ( solutionRoot , "LanMountainDesktop" , "bin" , "Debug" , "net10.0" , executable ) ,
Path . Combine ( solutionRoot , "LanMountainDesktop" , "bin" , "Release" , "net10.0" , executable ) ,
// 向后兼容:如果 Launcher 在特殊目录结构中
2026-04-21 20:59:52 +08:00
Path . Combine ( launcherDir , ".." , ".." , "LanMountainDesktop" , "bin" , "Debug" , "net10.0" , executable ) ,
Path . Combine ( launcherDir , ".." , ".." , "LanMountainDesktop" , "bin" , "Release" , "net10.0" , executable ) ,
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
// dev-test 目录
Path . Combine ( solutionRoot , "dev-test" , "app-1.0.0-dev" , executable ) ,
2026-04-21 20:59:52 +08:00
} ;
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
2026-04-21 20:59:52 +08:00
return possiblePaths . Select ( Path . GetFullPath ) . Distinct ( ) ;
}
public string GetCurrentVersion ( )
{
var deployment = FindCurrentDeploymentDirectory ( ) ;
if ( string . IsNullOrWhiteSpace ( deployment ) )
{
return "0.0.0" ;
}
return ParseVersionTextFromDirectory ( deployment ) ? ? "0.0.0" ;
}
public string BuildNextDeploymentDirectory ( string targetVersion )
{
var sanitized = string . IsNullOrWhiteSpace ( targetVersion ) ? "0.0.0" : targetVersion . Trim ( ) ;
var index = 0 ;
while ( true )
{
var candidate = Path . Combine ( _appRoot , $"app-{sanitized}-{index.ToString(CultureInfo.InvariantCulture)}" ) ;
if ( ! Directory . Exists ( candidate ) )
{
return candidate ;
}
index + + ;
}
}
/// <summary>
2026-04-23 00:27:01 +08:00
/// 娓呯悊鏃х 増鏈儴缃诧紝淇濈暀鏈€杩戠殑N涓増鏈? /// </summary>
/// <param name="minVersionsToKeep">鏈€灏戜繚鐣欑増鏈暟锛岄粯璁?涓?/param>
2026-04-21 20:59:52 +08:00
public void CleanupOldDeployments ( int minVersionsToKeep = 3 )
{
try
{
Console . WriteLine ( $"[DeploymentLocator] Starting cleanup with retention policy: keep at least {minVersionsToKeep} versions" ) ;
if ( ! Directory . Exists ( _appRoot ) )
{
return ;
}
var candidates = Directory . GetDirectories ( _appRoot , "app-*" , SearchOption . TopDirectoryOnly ) ;
var validDeployments = candidates
. Where ( path = > ! File . Exists ( Path . Combine ( path , ".partial" ) ) )
. Select ( path = > new
{
Path = path ,
Version = ParseVersionFromDirectory ( path ) ,
IsDestroyed = File . Exists ( Path . Combine ( path , ".destroy" ) ) ,
IsCurrent = File . Exists ( Path . Combine ( path , ".current" ) )
} )
. OrderByDescending ( item = > item . Version )
. ToList ( ) ;
Console . WriteLine ( $"[DeploymentLocator] Found {validDeployments.Count} valid deployments" ) ;
2026-04-23 00:27:01 +08:00
// 纭畾瑕佷繚鐣欑殑鐗堟湰
2026-04-21 20:59:52 +08:00
var versionsToKeep = new HashSet < string > ( ) ;
2026-04-23 00:27:01 +08:00
// 1. 鎬绘槸淇濈暀褰撳墠鐗堟湰
2026-04-21 20:59:52 +08:00
var currentVersion = validDeployments . FirstOrDefault ( d = > d . IsCurrent ) ;
if ( currentVersion ! = null )
{
versionsToKeep . Add ( currentVersion . Path ) ;
Console . WriteLine ( $"[DeploymentLocator] Keep current version: {currentVersion.Path}" ) ;
}
2026-04-23 00:27:01 +08:00
// 2. 淇濈暀鏈€杩戠殑N涓湁鏁堢増鏈紙涓嶅寘鎷凡鏍囪destroy鐨勶級
2026-04-21 20:59:52 +08:00
var activeVersions = validDeployments
. Where ( d = > ! d . IsDestroyed )
. Take ( minVersionsToKeep )
. ToList ( ) ;
foreach ( var ver in activeVersions )
{
versionsToKeep . Add ( ver . Path ) ;
Console . WriteLine ( $"[DeploymentLocator] Keep recent version: {ver.Path}" ) ;
}
2026-04-23 00:27:01 +08:00
// 3. 淇濈暀鏈夊揩鐓х殑鐗堟湰锛堢敤浜庡洖婊氾級
Launcher fix (#6)
* fix.hy3试图修复中
* Resolve dev paths and fix splash UI thread
Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown.
* Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
* Add dev/debug startup flow and launch profiles
Handle design-time initialization and add a developer debug startup path: App now skips normal startup when in design mode and shows a DevDebugWindow when running in debug (unless a preview or apply-update command). CommandContext.IsDebugMode is extended to include DOTNET_ENVIRONMENT=Development via a new IsDevelopmentEnvironment helper. Program.Main and BuildAvaloniaApp are made public to aid tooling. Added multiple launchSettings profiles for debug and preview commands that set DOTNET_ENVIRONMENT=Development to simplify IDE debugging and UI previewing.
* Simplify splash to fade; add themed about banners
Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
* Use AppJsonContext for startup state serialization
Switch serialization to the source-generated System.Text.Json context: add JsonSerializable(typeof(StartupAttemptRecord)) to AppJsonContext and replace the previous JsonSerializerOptions-based Serialize/Deserialize calls with AppJsonContext.Default.StartupAttemptRecord. Also remove the now-unused SerializerOptions field. Additionally, update .gitignore to exclude /test-aot-publish.
* Add OOBE redesign, theme & data location support
Introduce a redesigned OOBE flow and data-location/theme support across the launcher. Adds a new ThemeService for applying light/dark and accent colors; integrates FluentIcons.Avalonia package for icons. Overhauls OobeWindow (UX animations, typing effect, multi-step theme and data-location pages, Monet options, and final welcome step) and its code-behind to handle step navigation, accent selection, and data-location resolution. Adds DataLocation UI and handlers (DataLocationPromptWindow changes, DataLocation resolver usage) and wires a DevDebug UI for toggling/opening the data-location page. UpdateEngineService now resolves the launcher root via DataLocationResolver. Misc: update various view models, localization entries and remove TrimmerRoots.xml.
* Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:41:26 +08:00
var resolver = new DataLocationResolver ( _appRoot ) ;
var snapshotDir = Path . Combine ( resolver . ResolveLauncherDataPath ( ) , "snapshots" ) ;
2026-04-21 20:59:52 +08:00
if ( Directory . Exists ( snapshotDir ) )
{
try
{
var snapshotFiles = Directory . GetFiles ( snapshotDir , "*.json" , SearchOption . TopDirectoryOnly ) ;
foreach ( var snapshotFile in snapshotFiles )
{
try
{
var json = File . ReadAllText ( snapshotFile ) ;
var snapshot = System . Text . Json . JsonSerializer . Deserialize ( json , AppJsonContext . Default . SnapshotMetadata ) ;
if ( snapshot ! = null & & ! string . IsNullOrEmpty ( snapshot . SourceDirectory ) )
{
if ( Directory . Exists ( snapshot . SourceDirectory ) )
{
versionsToKeep . Add ( snapshot . SourceDirectory ) ;
Console . WriteLine ( $"[DeploymentLocator] Keep version for rollback: {snapshot.SourceDirectory}" ) ;
}
}
}
catch
{
2026-04-23 00:27:01 +08:00
// 蹇界暐蹇収瑙f瀽閿欒
2026-04-21 20:59:52 +08:00
}
}
}
catch
{
2026-04-23 00:27:01 +08:00
// 蹇界暐蹇収鐩綍璁块棶閿欒
2026-04-21 20:59:52 +08:00
}
}
2026-04-23 00:27:01 +08:00
// 娓呯悊涓嶉渶瑕佺殑鐗堟湰
2026-04-21 20:59:52 +08:00
foreach ( var deployment in validDeployments )
{
if ( versionsToKeep . Contains ( deployment . Path ) )
{
if ( deployment . IsDestroyed )
{
try
{
File . Delete ( Path . Combine ( deployment . Path , ".destroy" ) ) ;
Console . WriteLine ( $"[DeploymentLocator] Unmarked for deletion (kept): {deployment.Path}" ) ;
}
catch
{
2026-04-23 00:27:01 +08:00
// 蹇界暐鍙栨秷鏍囪澶辫触
2026-04-21 20:59:52 +08:00
}
}
continue ;
}
if ( ! deployment . IsDestroyed )
{
try
{
File . WriteAllText ( Path . Combine ( deployment . Path , ".destroy" ) , string . Empty ) ;
Console . WriteLine ( $"[DeploymentLocator] Marked for deletion: {deployment.Path}" ) ;
}
catch
{
2026-04-23 00:27:01 +08:00
// 蹇界暐鏍囪澶辫触
2026-04-21 20:59:52 +08:00
}
}
2026-04-23 00:27:01 +08:00
// 灏濊瘯鍒犻櫎
2026-04-21 20:59:52 +08:00
try
{
Directory . Delete ( deployment . Path , recursive : true ) ;
Console . WriteLine ( $"[DeploymentLocator] Deleted: {deployment.Path}" ) ;
}
catch
{
2026-04-23 00:27:01 +08:00
// 蹇界暐鍒犻櫎澶辫触(鍙兘鏂囦欢琚崰鐢?,涓嬫鍚姩鍐嶈瘯
2026-04-21 20:59:52 +08:00
Console . WriteLine ( $"[DeploymentLocator] Failed to delete (will retry later): {deployment.Path}" ) ;
}
}
}
catch ( Exception ex )
{
Console . Error . WriteLine ( $"[DeploymentLocator] Cleanup failed: {ex.Message}" ) ;
2026-04-23 00:27:01 +08:00
// 蹇界暐娓呯悊澶辫触
2026-04-21 20:59:52 +08:00
}
}
/// <summary>
2026-04-23 00:27:01 +08:00
/// 浠呮竻鐞嗗凡鏍囪涓?destroy鐨勯儴缃诧紙鍏煎鏃ф柟娉曪級
2026-04-21 20:59:52 +08:00
/// </summary>
[Obsolete("Use CleanupOldDeployments instead")]
public void CleanupDestroyedDeployments ( )
{
CleanupOldDeployments ( 3 ) ;
}
public static Version ParseVersionFromDirectory ( string path )
{
var text = ParseVersionTextFromDirectory ( path ) ;
return Version . TryParse ( text , out var version ) ? version : new Version ( 0 , 0 , 0 ) ;
}
private static string? ParseVersionTextFromDirectory ( string path )
{
var fileName = Path . GetFileName ( path ) ;
if ( string . IsNullOrWhiteSpace ( fileName ) )
{
return null ;
}
var segments = fileName . Split ( '-' ) ;
if ( segments . Length < 2 )
{
return null ;
}
return segments [ 1 ] ;
}
/// <summary>
2026-04-23 00:27:01 +08:00
/// 浠庨儴缃茬洰褰曡鍙栫増鏈俊鎭? /// </summary>
2026-04-21 20:59:52 +08:00
public AppVersionInfo GetVersionInfo ( )
{
2026-04-23 00:27:01 +08:00
var executableName = OperatingSystem . IsWindows ( ) ? "LanMountainDesktop.exe" : "LanMountainDesktop" ;
var resolved = AppVersionProvider . ResolveFromPackageRoot ( _appRoot , executableName ) ;
return string . IsNullOrWhiteSpace ( resolved . Version )
? new AppVersionInfo
2026-04-21 20:59:52 +08:00
{
2026-04-23 00:27:01 +08:00
Version = GetCurrentVersion ( ) ,
Codename = "Administrate"
2026-04-21 20:59:52 +08:00
}
2026-04-23 00:27:01 +08:00
: resolved ;
}
2026-04-21 20:59:52 +08:00
}