diff --git a/LanMountainDesktop.Launcher/Services/DataLocationOobeStep.cs b/LanMountainDesktop.Launcher/Services/DataLocationOobeStep.cs
index 1abf73d..67e40a2 100644
--- a/LanMountainDesktop.Launcher/Services/DataLocationOobeStep.cs
+++ b/LanMountainDesktop.Launcher/Services/DataLocationOobeStep.cs
@@ -43,11 +43,11 @@ internal sealed class DataLocationOobeStep : IOobeStep
if (result is null)
{
Logger.Info("DataLocation OOBE step: user cancelled or closed window. Using default system location.");
- _resolver.ApplyLocationChoice(DataLocationMode.System, false);
+ _resolver.ApplyLocationChoice(DataLocationMode.System, null, false);
}
else
{
- var success = _resolver.ApplyLocationChoice(result.SelectedMode, result.MigrateExistingData);
+ var success = _resolver.ApplyLocationChoice(result.SelectedMode, null, result.MigrateExistingData);
Logger.Info(
$"DataLocation OOBE step: user selected '{result.SelectedMode}'. " +
$"Migrate={result.MigrateExistingData}; Success={success}.");
diff --git a/LanMountainDesktop.Launcher/Services/DataLocationResolver.cs b/LanMountainDesktop.Launcher/Services/DataLocationResolver.cs
index ae82021..860b884 100644
--- a/LanMountainDesktop.Launcher/Services/DataLocationResolver.cs
+++ b/LanMountainDesktop.Launcher/Services/DataLocationResolver.cs
@@ -6,16 +6,15 @@ namespace LanMountainDesktop.Launcher.Services;
internal sealed class DataLocationResolver
{
private const string ConfigFileName = "data-location.config.json";
- private const string PortableDataFolderName = "AppData";
+ private const string LauncherFolderName = "Launcher";
+ private const string DesktopFolderName = "Desktop";
private readonly string _appRoot;
- private readonly string _configPath;
private readonly string _defaultSystemDataPath;
public DataLocationResolver(string appRoot)
{
_appRoot = Path.GetFullPath(appRoot);
- _configPath = Path.Combine(_appRoot, ConfigFileName);
_defaultSystemDataPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"LanMountainDesktop");
@@ -23,12 +22,19 @@ internal sealed class DataLocationResolver
public string AppRoot => _appRoot;
- public string ConfigPath => _configPath;
-
+ ///
+ /// 默认系统数据路径(用户目录)
+ ///
public string DefaultSystemDataPath => _defaultSystemDataPath;
- public string DefaultPortableDataPath => Path.Combine(_appRoot, PortableDataFolderName);
+ ///
+ /// 默认便携模式数据路径(应用目录下的 AppData)
+ ///
+ public string DefaultPortableDataPath => Path.Combine(_appRoot, "AppData");
+ ///
+ /// 检查是否允许便携模式(应用目录是否可写)
+ ///
public bool IsPortableModeAllowed()
{
try
@@ -44,40 +50,9 @@ internal sealed class DataLocationResolver
}
}
- public DataLocationConfig? LoadConfig()
- {
- try
- {
- if (!File.Exists(_configPath))
- {
- return null;
- }
-
- var json = File.ReadAllText(_configPath);
- return JsonSerializer.Deserialize(json, AppJsonContext.Default.DataLocationConfig);
- }
- catch (Exception ex)
- {
- Logger.Warn($"Failed to load data location config from '{_configPath}'. Error='{ex.Message}'.");
- return null;
- }
- }
-
- public bool SaveConfig(DataLocationConfig config)
- {
- try
- {
- var json = JsonSerializer.Serialize(config, AppJsonContext.Default.DataLocationConfig);
- File.WriteAllText(_configPath, json);
- return true;
- }
- catch (Exception ex)
- {
- Logger.Warn($"Failed to save data location config to '{_configPath}'. Error='{ex.Message}'.");
- return false;
- }
- }
-
+ ///
+ /// 解析数据根目录(用户选择的位置)
+ ///
public string ResolveDataRoot()
{
var config = LoadConfig();
@@ -90,7 +65,7 @@ internal sealed class DataLocationResolver
{
var portablePath = !string.IsNullOrWhiteSpace(config.PortableDataPath)
? config.PortableDataPath
- : DefaultPortableDataPath;
+ : _defaultSystemDataPath;
return Path.GetFullPath(portablePath);
}
@@ -99,6 +74,46 @@ internal sealed class DataLocationResolver
: _defaultSystemDataPath;
}
+ ///
+ /// 启动器数据目录(日志、配置、状态等)
+ ///
+ public string ResolveLauncherDataPath()
+ {
+ return Path.Combine(ResolveDataRoot(), LauncherFolderName);
+ }
+
+ ///
+ /// 桌面应用数据目录(组件、设置、插件等)
+ ///
+ public string ResolveDesktopDataPath()
+ {
+ return Path.Combine(ResolveDataRoot(), DesktopFolderName);
+ }
+
+ ///
+ /// 数据位置配置文件路径(保存在 Launcher 目录下)
+ ///
+ public string ResolveConfigPath()
+ {
+ return Path.Combine(ResolveLauncherDataPath(), ConfigFileName);
+ }
+
+ ///
+ /// 启动器日志目录
+ ///
+ public string ResolveLauncherLogsPath()
+ {
+ return Path.Combine(ResolveLauncherDataPath(), "logs");
+ }
+
+ ///
+ /// 启动器状态目录
+ ///
+ public string ResolveLauncherStatePath()
+ {
+ return Path.Combine(ResolveLauncherDataPath(), "state");
+ }
+
public DataLocationMode ResolveMode()
{
var config = LoadConfig();
@@ -112,116 +127,127 @@ internal sealed class DataLocationResolver
: DataLocationMode.System;
}
+ public DataLocationConfig? LoadConfig()
+ {
+ try
+ {
+ var configPath = ResolveConfigPath();
+ if (!File.Exists(configPath))
+ {
+ return null;
+ }
+
+ var json = File.ReadAllText(configPath);
+ return JsonSerializer.Deserialize(json, AppJsonContext.Default.DataLocationConfig);
+ }
+ catch (Exception ex)
+ {
+ Logger.Warn($"Failed to load data location config. Error='{ex.Message}'.");
+ return null;
+ }
+ }
+
+ public bool SaveConfig(DataLocationConfig config)
+ {
+ try
+ {
+ var launcherPath = ResolveLauncherDataPath();
+ Directory.CreateDirectory(launcherPath);
+
+ var configPath = ResolveConfigPath();
+ var json = JsonSerializer.Serialize(config, AppJsonContext.Default.DataLocationConfig);
+ File.WriteAllText(configPath, json);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logger.Warn($"Failed to save data location config. Error='{ex.Message}'.");
+ return false;
+ }
+ }
+
+ public bool ApplyLocationChoice(DataLocationMode mode, string? customPath = null, bool migrateExistingData = false)
+ {
+ var targetDataRoot = mode == DataLocationMode.Portable && !string.IsNullOrWhiteSpace(customPath)
+ ? Path.GetFullPath(customPath)
+ : _defaultSystemDataPath;
+
+ var config = new DataLocationConfig
+ {
+ DataLocationMode = mode.ToString(),
+ SystemDataPath = _defaultSystemDataPath,
+ PortableDataPath = mode == DataLocationMode.Portable ? targetDataRoot : null
+ };
+
+ // 先创建目录结构
+ try
+ {
+ Directory.CreateDirectory(ResolveLauncherDataPath());
+ Directory.CreateDirectory(ResolveDesktopDataPath());
+ }
+ catch (Exception ex)
+ {
+ Logger.Warn($"Failed to create data directories. Error='{ex.Message}'.");
+ return false;
+ }
+
+ // 保存配置
+ if (!SaveConfig(config))
+ {
+ return false;
+ }
+
+ if (migrateExistingData && mode == DataLocationMode.Portable)
+ {
+ MigrateSystemDataToPortable(targetDataRoot);
+ }
+
+ return true;
+ }
+
public bool HasExistingSystemData()
{
- var systemPath = _defaultSystemDataPath;
- if (!Directory.Exists(systemPath))
+ var desktopPath = Path.Combine(_defaultSystemDataPath, DesktopFolderName);
+ if (!Directory.Exists(desktopPath))
{
return false;
}
var markerFiles = new[]
{
- Path.Combine(systemPath, "settings.json"),
- Path.Combine(systemPath, "launcher-settings.json"),
- Path.Combine(systemPath, "component-state.db"),
- Path.Combine(systemPath, "app.db")
+ Path.Combine(desktopPath, "settings.json"),
+ Path.Combine(desktopPath, "component-state.db"),
+ Path.Combine(desktopPath, "app.db")
};
return markerFiles.Any(File.Exists);
}
- public bool ApplyLocationChoice(DataLocationMode mode, bool migrateExistingData)
- {
- var config = new DataLocationConfig
- {
- DataLocationMode = mode.ToString(),
- SystemDataPath = _defaultSystemDataPath,
- PortableDataPath = DefaultPortableDataPath
- };
-
- if (!SaveConfig(config))
- {
- return false;
- }
-
- var targetDataRoot = mode == DataLocationMode.Portable
- ? DefaultPortableDataPath
- : _defaultSystemDataPath;
-
- try
- {
- Directory.CreateDirectory(targetDataRoot);
- }
- catch (Exception ex)
- {
- Logger.Warn($"Failed to create data directory '{targetDataRoot}'. Error='{ex.Message}'.");
- return false;
- }
-
- if (migrateExistingData && mode == DataLocationMode.Portable)
- {
- MigrateSystemDataToPortable();
- }
-
- return true;
- }
-
- private void MigrateSystemDataToPortable()
+ private void MigrateSystemDataToPortable(string targetDataRoot)
{
if (!HasExistingSystemData())
{
return;
}
- var sourcePath = _defaultSystemDataPath;
- var targetPath = DefaultPortableDataPath;
+ var sourceDesktopPath = Path.Combine(_defaultSystemDataPath, DesktopFolderName);
+ var targetDesktopPath = Path.Combine(targetDataRoot, DesktopFolderName);
try
{
- Directory.CreateDirectory(targetPath);
+ Directory.CreateDirectory(targetDesktopPath);
- var filesToMigrate = Directory.GetFiles(sourcePath, "*", SearchOption.TopDirectoryOnly);
- foreach (var file in filesToMigrate)
+ // 迁移桌面数据
+ if (Directory.Exists(sourceDesktopPath))
{
- var fileName = Path.GetFileName(file);
- var destFile = Path.Combine(targetPath, fileName);
- try
- {
- File.Copy(file, destFile, overwrite: true);
- }
- catch (Exception ex)
- {
- Logger.Warn($"Failed to migrate file '{fileName}'. Error='{ex.Message}'.");
- }
+ CopyDirectory(sourceDesktopPath, targetDesktopPath);
}
- var dirsToMigrate = Directory.GetDirectories(sourcePath, "*", SearchOption.TopDirectoryOnly);
- foreach (var dir in dirsToMigrate)
- {
- var dirName = Path.GetFileName(dir);
- if (string.Equals(dirName, ".launcher", StringComparison.OrdinalIgnoreCase) &&
- string.Equals(Path.GetFileName(sourcePath), "LanMountainDesktop", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- var destDir = Path.Combine(targetPath, dirName);
- try
- {
- CopyDirectory(dir, destDir);
- }
- catch (Exception ex)
- {
- Logger.Warn($"Failed to migrate directory '{dirName}'. Error='{ex.Message}'.");
- }
- }
-
- Logger.Info($"Data migration completed. Source='{sourcePath}'; Target='{targetPath}'.");
+ Logger.Info($"Data migration completed. Target='{targetDataRoot}'.");
}
catch (Exception ex)
{
- Logger.Warn($"Data migration failed. Source='{sourcePath}'; Target='{targetPath}'. Error='{ex.Message}'.");
+ Logger.Warn($"Data migration failed. Target='{targetDataRoot}'. Error='{ex.Message}'.");
}
}
diff --git a/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs b/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs
index 15e4c85..7ba3430 100644
--- a/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs
+++ b/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs
@@ -497,7 +497,8 @@ internal sealed class DeploymentLocator
}
// 3. 淇濈暀鏈夊揩鐓х殑鐗堟湰锛堢敤浜庡洖婊氾級
- var snapshotDir = Path.Combine(_appRoot, ".launcher", "snapshots");
+ var resolver = new DataLocationResolver(_appRoot);
+ var snapshotDir = Path.Combine(resolver.ResolveLauncherDataPath(), "snapshots");
if (Directory.Exists(snapshotDir))
{
try
diff --git a/LanMountainDesktop.Launcher/Services/LauncherBackgroundService.cs b/LanMountainDesktop.Launcher/Services/LauncherBackgroundService.cs
new file mode 100644
index 0000000..d39f4ad
--- /dev/null
+++ b/LanMountainDesktop.Launcher/Services/LauncherBackgroundService.cs
@@ -0,0 +1,174 @@
+using Avalonia.Media.Imaging;
+
+namespace LanMountainDesktop.Launcher.Services;
+
+///
+/// 启动器背景图片服务
+///
+internal static class LauncherBackgroundService
+{
+ private const string PictureFileName = "Launcher Picture";
+ private const long MaxFileSize = 10 * 1024 * 1024; // 10MB
+ private const double WindowAspectRatio = 7.0 / 5.0; // 700:500
+ private const double AspectRatioTolerance = 0.15; // 15% 误差
+
+ private static Bitmap? _cachedBitmap;
+ private static string? _cachedPath;
+
+ ///
+ /// 背景图片信息
+ ///
+ public record BackgroundImageInfo
+ {
+ public required bool Exists { get; init; }
+ public required bool IsValid { get; init; }
+ public string? FilePath { get; init; }
+ public Bitmap? Bitmap { get; init; }
+ public int Width { get; init; }
+ public int Height { get; init; }
+ public double AspectRatio { get; init; }
+ public string? ErrorMessage { get; init; }
+ }
+
+ ///
+ /// 加载背景图片
+ ///
+ public static BackgroundImageInfo LoadBackgroundImage()
+ {
+ try
+ {
+ var resolver = new DataLocationResolver(AppContext.BaseDirectory);
+ var launcherPath = resolver.ResolveLauncherDataPath();
+
+ // 查找图片文件
+ var imagePath = FindImageFile(launcherPath);
+ if (imagePath == null)
+ {
+ return new BackgroundImageInfo
+ {
+ Exists = false,
+ IsValid = false,
+ ErrorMessage = "未找到背景图片文件"
+ };
+ }
+
+ // 检查文件大小
+ var fileInfo = new FileInfo(imagePath);
+ if (fileInfo.Length > MaxFileSize)
+ {
+ return new BackgroundImageInfo
+ {
+ Exists = true,
+ IsValid = false,
+ FilePath = imagePath,
+ ErrorMessage = $"图片文件过大 ({fileInfo.Length / 1024 / 1024}MB > 10MB)"
+ };
+ }
+
+ // 使用缓存
+ if (_cachedBitmap != null && _cachedPath == imagePath)
+ {
+ return new BackgroundImageInfo
+ {
+ Exists = true,
+ IsValid = true,
+ FilePath = imagePath,
+ Bitmap = _cachedBitmap,
+ Width = _cachedBitmap.PixelSize.Width,
+ Height = _cachedBitmap.PixelSize.Height,
+ AspectRatio = (double)_cachedBitmap.PixelSize.Width / _cachedBitmap.PixelSize.Height
+ };
+ }
+
+ // 加载图片
+ var bitmap = new Bitmap(imagePath);
+ var width = bitmap.PixelSize.Width;
+ var height = bitmap.PixelSize.Height;
+ var aspectRatio = (double)width / height;
+
+ // 校验比例
+ var ratioDiff = Math.Abs(aspectRatio - WindowAspectRatio) / WindowAspectRatio;
+ if (ratioDiff > AspectRatioTolerance)
+ {
+ bitmap.Dispose();
+ return new BackgroundImageInfo
+ {
+ Exists = true,
+ IsValid = false,
+ FilePath = imagePath,
+ Width = width,
+ Height = height,
+ AspectRatio = aspectRatio,
+ ErrorMessage = $"图片比例不符合要求 ({aspectRatio:F2},需要接近 {WindowAspectRatio:F2})"
+ };
+ }
+
+ // 缓存图片
+ _cachedBitmap = bitmap;
+ _cachedPath = imagePath;
+
+ Logger.Info($"[LauncherBackground] 背景图片加载成功: {imagePath} ({width}x{height}, 比例: {aspectRatio:F2})");
+
+ return new BackgroundImageInfo
+ {
+ Exists = true,
+ IsValid = true,
+ FilePath = imagePath,
+ Bitmap = bitmap,
+ Width = width,
+ Height = height,
+ AspectRatio = aspectRatio
+ };
+ }
+ catch (Exception ex)
+ {
+ Logger.Warn($"[LauncherBackground] 加载背景图片失败: {ex.Message}");
+ return new BackgroundImageInfo
+ {
+ Exists = false,
+ IsValid = false,
+ ErrorMessage = $"加载失败: {ex.Message}"
+ };
+ }
+ }
+
+ ///
+ /// 查找图片文件
+ ///
+ private static string? FindImageFile(string directory)
+ {
+ var extensions = new[] { ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp" };
+
+ foreach (var ext in extensions)
+ {
+ var path = Path.Combine(directory, PictureFileName + ext);
+ if (File.Exists(path))
+ {
+ return path;
+ }
+ }
+
+ // 也尝试不带扩展名的匹配(如果文件本身就有扩展名)
+ var files = Directory.GetFiles(directory, PictureFileName + ".*");
+ foreach (var file in files)
+ {
+ var ext = Path.GetExtension(file).ToLowerInvariant();
+ if (extensions.Contains(ext))
+ {
+ return file;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// 清除缓存
+ ///
+ public static void ClearCache()
+ {
+ _cachedBitmap?.Dispose();
+ _cachedBitmap = null;
+ _cachedPath = null;
+ }
+}
diff --git a/LanMountainDesktop.Launcher/Services/LauncherDebugSettingsStore.cs b/LanMountainDesktop.Launcher/Services/LauncherDebugSettingsStore.cs
index 6ea9d68..9ed4cad 100644
--- a/LanMountainDesktop.Launcher/Services/LauncherDebugSettingsStore.cs
+++ b/LanMountainDesktop.Launcher/Services/LauncherDebugSettingsStore.cs
@@ -104,7 +104,7 @@ internal static class LauncherDebugSettingsStore
{
var appRoot = Commands.ResolveAppRoot(CommandContext.FromArgs([]));
var resolver = new DataLocationResolver(appRoot);
- return Path.Combine(resolver.ResolveDataRoot(), ".launcher");
+ return resolver.ResolveLauncherDataPath();
}
catch
{
@@ -115,7 +115,7 @@ internal static class LauncherDebugSettingsStore
var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (!string.IsNullOrWhiteSpace(appData))
{
- return Path.Combine(appData, "LanMountainDesktop", ".launcher");
+ return Path.Combine(appData, "LanMountainDesktop", "Launcher");
}
}
catch
@@ -124,11 +124,11 @@ internal static class LauncherDebugSettingsStore
try
{
- return Path.Combine(AppContext.BaseDirectory, ".launcher");
+ return Path.Combine(AppContext.BaseDirectory, "Launcher");
}
catch
{
- return Path.Combine(Directory.GetCurrentDirectory(), ".launcher");
+ return Path.Combine(Directory.GetCurrentDirectory(), "Launcher");
}
}
}
diff --git a/LanMountainDesktop.Launcher/Services/Logger.cs b/LanMountainDesktop.Launcher/Services/Logger.cs
index 0e474a9..a76e987 100644
--- a/LanMountainDesktop.Launcher/Services/Logger.cs
+++ b/LanMountainDesktop.Launcher/Services/Logger.cs
@@ -57,7 +57,7 @@ internal static class Logger
{
var appRoot = Commands.ResolveAppRoot(CommandContext.FromArgs([]));
var resolver = new DataLocationResolver(appRoot);
- return Path.Combine(resolver.ResolveDataRoot(), ".launcher", "logs");
+ return resolver.ResolveLauncherLogsPath();
}
catch
{
@@ -68,7 +68,7 @@ internal static class Logger
var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (!string.IsNullOrEmpty(appData))
{
- return Path.Combine(appData, "LanMountainDesktop", ".launcher", "logs");
+ return Path.Combine(appData, "LanMountainDesktop", "Launcher", "logs");
}
}
catch
@@ -78,7 +78,7 @@ internal static class Logger
try
{
var launcherDir = AppContext.BaseDirectory;
- return Path.Combine(launcherDir, ".launcher", "logs");
+ return Path.Combine(launcherDir, "Launcher", "logs");
}
catch
{
diff --git a/LanMountainDesktop.Launcher/Services/OobeStateService.cs b/LanMountainDesktop.Launcher/Services/OobeStateService.cs
index 39c8f03..9ecca79 100644
--- a/LanMountainDesktop.Launcher/Services/OobeStateService.cs
+++ b/LanMountainDesktop.Launcher/Services/OobeStateService.cs
@@ -23,7 +23,7 @@ internal sealed class OobeStateService
var stateRoot = string.IsNullOrWhiteSpace(stateRootOverride)
? ResolveStateRoot(appRoot)
: Path.GetFullPath(stateRootOverride);
- _stateDirectory = Path.Combine(stateRoot, ".launcher", "state");
+ _stateDirectory = Path.Combine(stateRoot, "Launcher", "state");
_statePath = Path.Combine(_stateDirectory, "oobe-state.json");
_legacyMarkerPath = Path.Combine(_stateDirectory, "first_run_completed");
}
diff --git a/LanMountainDesktop.Launcher/Services/StartupAttemptRegistry.cs b/LanMountainDesktop.Launcher/Services/StartupAttemptRegistry.cs
index 6291c58..c9ebd30 100644
--- a/LanMountainDesktop.Launcher/Services/StartupAttemptRegistry.cs
+++ b/LanMountainDesktop.Launcher/Services/StartupAttemptRegistry.cs
@@ -26,14 +26,14 @@ internal sealed class StartupAttemptRegistry
{
var appRoot = Commands.ResolveAppRoot(CommandContext.FromArgs([]));
var resolver = new DataLocationResolver(appRoot);
- return Path.Combine(resolver.ResolveDataRoot(), ".launcher", "state", "startup-attempt.json");
+ return Path.Combine(resolver.ResolveLauncherStatePath(), "startup-attempt.json");
}
catch
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"LanMountainDesktop",
- ".launcher",
+ "Launcher",
"state",
"startup-attempt.json");
}
diff --git a/LanMountainDesktop.Launcher/Services/UpdateEngineService.cs b/LanMountainDesktop.Launcher/Services/UpdateEngineService.cs
index 7c008d7..727a117 100644
--- a/LanMountainDesktop.Launcher/Services/UpdateEngineService.cs
+++ b/LanMountainDesktop.Launcher/Services/UpdateEngineService.cs
@@ -7,7 +7,6 @@ namespace LanMountainDesktop.Launcher.Services;
internal sealed class UpdateEngineService
{
- private const string LauncherDirectoryName = ".launcher";
private const string UpdateDirectoryName = "update";
private const string IncomingDirectoryName = "incoming";
private const string SnapshotsDirectoryName = "snapshots";
@@ -22,7 +21,6 @@ internal sealed class UpdateEngineService
private readonly DeploymentLocator _deploymentLocator;
private readonly string _appRoot;
- private readonly string _dataRoot;
private readonly string _launcherRoot;
private readonly string _incomingRoot;
private readonly string _snapshotsRoot;
@@ -31,8 +29,8 @@ internal sealed class UpdateEngineService
{
_deploymentLocator = deploymentLocator;
_appRoot = deploymentLocator.GetAppRoot();
- _dataRoot = new DataLocationResolver(_appRoot).ResolveDataRoot();
- _launcherRoot = Path.Combine(_dataRoot, LauncherDirectoryName);
+ var resolver = new DataLocationResolver(_appRoot);
+ _launcherRoot = resolver.ResolveLauncherDataPath();
_incomingRoot = Path.Combine(_launcherRoot, UpdateDirectoryName, IncomingDirectoryName);
_snapshotsRoot = Path.Combine(_launcherRoot, SnapshotsDirectoryName);
}
diff --git a/LanMountainDesktop.Launcher/Views/OobeWindow.axaml b/LanMountainDesktop.Launcher/Views/OobeWindow.axaml
index 313e442..b8b2f48 100644
--- a/LanMountainDesktop.Launcher/Views/OobeWindow.axaml
+++ b/LanMountainDesktop.Launcher/Views/OobeWindow.axaml
@@ -23,7 +23,6 @@
-
diff --git a/LanMountainDesktop.Launcher/Views/OobeWindow.axaml.cs b/LanMountainDesktop.Launcher/Views/OobeWindow.axaml.cs
index ceff7e7..8fc5eae 100644
--- a/LanMountainDesktop.Launcher/Views/OobeWindow.axaml.cs
+++ b/LanMountainDesktop.Launcher/Views/OobeWindow.axaml.cs
@@ -431,7 +431,7 @@ public partial class OobeWindow : Window
// 应用数据位置选择
if (!_isDebugMode)
{
- _resolver.ApplyLocationChoice(_selectedDataLocationMode, _migrateExistingData);
+ _resolver.ApplyLocationChoice(_selectedDataLocationMode, null, _migrateExistingData);
}
await NavigateToStep(4);
diff --git a/LanMountainDesktop.Launcher/Views/SplashWindow.axaml b/LanMountainDesktop.Launcher/Views/SplashWindow.axaml
index 729bcc8..21bac27 100644
--- a/LanMountainDesktop.Launcher/Views/SplashWindow.axaml
+++ b/LanMountainDesktop.Launcher/Views/SplashWindow.axaml
@@ -20,8 +20,20 @@
-
+
+
+
+
+
+
+
("VersionTextBorder") is { } versionBorder)
{
versionBorder.PointerPressed += OnVersionTextClick;
}
}
+ private void InitializeBackgroundImage()
+ {
+ try
+ {
+ var imageInfo = LauncherBackgroundService.LoadBackgroundImage();
+ if (imageInfo is { IsValid: true, Bitmap: not null })
+ {
+ if (this.FindControl("BackgroundImage") is { } backgroundImage)
+ {
+ backgroundImage.Source = imageInfo.Bitmap;
+ backgroundImage.IsVisible = true;
+ backgroundImage.Opacity = 1;
+ }
+ Logger.Info("[SplashWindow] 背景图片加载成功");
+ }
+ else if (imageInfo is { Exists: true, IsValid: false })
+ {
+ Logger.Warn($"[SplashWindow] 背景图片校验失败: {imageInfo.ErrorMessage}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Warn($"[SplashWindow] 加载背景图片失败: {ex.Message}");
+ }
+ }
+
private async void OnWindowOpened(object? sender, EventArgs e)
{
if (_isOpened)