mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
refactor(launcher): reorganize into responsibility folders
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services.AirApp;
|
namespace LanMountainDesktop.Launcher.AirApp;
|
||||||
|
|
||||||
internal sealed class AirAppHostLocator
|
internal sealed class AirAppHostLocator
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services.AirApp;
|
namespace LanMountainDesktop.Launcher.AirApp;
|
||||||
|
|
||||||
internal static class AirAppInstanceKey
|
internal static class AirAppInstanceKey
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.AirApp;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.AirApp;
|
|
||||||
|
|
||||||
internal interface IAirAppProcessStarter
|
internal interface IAirAppProcessStarter
|
||||||
{
|
{
|
||||||
@@ -60,7 +58,7 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter
|
|||||||
AddArgument(startInfo, "--source-placement-id", sourcePlacementId.Trim());
|
AddArgument(startInfo, "--source-placement-id", sourcePlacementId.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
LanMountainDesktop.Launcher.Services.Logger.Info(
|
Logger.Info(
|
||||||
$"Starting AirAppHost. AppId='{appId}'; InstanceKey='{instanceKey}'; HostPath='{hostPath}'; DataRoot='{dataRoot ?? string.Empty}'.");
|
$"Starting AirAppHost. AppId='{appId}'; InstanceKey='{instanceKey}'; HostPath='{hostPath}'; DataRoot='{dataRoot ?? string.Empty}'.");
|
||||||
var process = Process.Start(startInfo);
|
var process = Process.Start(startInfo);
|
||||||
if (process is not null)
|
if (process is not null)
|
||||||
@@ -70,12 +68,12 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LanMountainDesktop.Launcher.Services.Logger.Info(
|
Logger.Info(
|
||||||
$"AirAppHost exited. AppId='{appId}'; InstanceKey='{instanceKey}'; ProcessId={process.Id}; ExitCode={process.ExitCode}.");
|
$"AirAppHost exited. AppId='{appId}'; InstanceKey='{instanceKey}'; ProcessId={process.Id}; ExitCode={process.ExitCode}.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LanMountainDesktop.Launcher.Services.Logger.Warn($"Failed to log AirAppHost exit: {ex.Message}");
|
Logger.Warn($"Failed to log AirAppHost exit: {ex.Message}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using LanMountainDesktop.Shared.IPC;
|
using LanMountainDesktop.Shared.IPC;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.AirApp;
|
namespace LanMountainDesktop.Launcher.AirApp;
|
||||||
|
|
||||||
internal sealed class LauncherAirAppLifecycleIpcHost : IDisposable
|
internal sealed class LauncherAirAppLifecycleIpcHost : IDisposable
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.AirApp;
|
namespace LanMountainDesktop.Launcher.AirApp;
|
||||||
|
|
||||||
internal sealed class LauncherAirAppLifecycleService : IAirAppLifecycleService
|
internal sealed class LauncherAirAppLifecycleService : IAirAppLifecycleService
|
||||||
{
|
{
|
||||||
@@ -7,8 +7,6 @@ using Avalonia.Threading;
|
|||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Resources;
|
using LanMountainDesktop.Launcher.Resources;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
using LanMountainDesktop.Launcher.Services;
|
||||||
using LanMountainDesktop.Launcher.Services.AirApp;
|
|
||||||
using LanMountainDesktop.Launcher.Services.Ipc;
|
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC;
|
using LanMountainDesktop.Shared.IPC;
|
||||||
@@ -70,12 +68,12 @@ public partial class App : Application
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试模式:只显示 DevDebugWindow,不走正常启动流程
|
// è°?è¯?模å¼<C3A5>ï¼?å<>ªæ?¾ç¤º DevDebugWindowï¼?ä¸<C3A4>èµ°æ£å¸¸å<C2B8>¯å?¨æµ<C3A6>ç¨?
|
||||||
// 避免启动主程序后 Launcher 自动退出,导致开发者无法预览 UI
|
// é<EFBFBD>¿å?<3F>å<EFBFBD>¯å?¨ä¸»ç¨?åº<C3A5>å<EFBFBD>? Launcher è?ªå?¨é??å?ºï¼?导è?´å¼?å<>?è??æ? æ³?é¢?è§? UI
|
||||||
if (context.IsDebugMode && !context.IsPreviewCommand &&
|
if (context.IsDebugMode && !context.IsPreviewCommand &&
|
||||||
!string.Equals(context.Command, "apply-update", StringComparison.OrdinalIgnoreCase))
|
!string.Equals(context.Command, "apply-update", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.Info("Debug mode active — showing DevDebugWindow instead of normal launch flow.");
|
Logger.Info("Debug mode active â?? showing DevDebugWindow instead of normal launch flow.");
|
||||||
var devDebugWindow = new DevDebugWindow();
|
var devDebugWindow = new DevDebugWindow();
|
||||||
devDebugWindow.Show();
|
devDebugWindow.Show();
|
||||||
base.OnFrameworkInitializationCompleted();
|
base.OnFrameworkInitializationCompleted();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
using LanMountainDesktop.Launcher.Plugins;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
|
|
||||||
@@ -30,15 +30,10 @@ namespace LanMountainDesktop.Launcher;
|
|||||||
[JsonSerializable(typeof(PublicTaskbarStatus))]
|
[JsonSerializable(typeof(PublicTaskbarStatus))]
|
||||||
[JsonSerializable(typeof(PublicShellActivationResult))]
|
[JsonSerializable(typeof(PublicShellActivationResult))]
|
||||||
[JsonSerializable(typeof(LauncherResult))]
|
[JsonSerializable(typeof(LauncherResult))]
|
||||||
[JsonSerializable(typeof(HostDiscoveryConfig))]
|
|
||||||
[JsonSerializable(typeof(PluginManifest))]
|
[JsonSerializable(typeof(PluginManifest))]
|
||||||
[JsonSerializable(typeof(PendingUpgrade))]
|
|
||||||
[JsonSerializable(typeof(List<PendingUpgrade>))]
|
[JsonSerializable(typeof(List<PendingUpgrade>))]
|
||||||
[JsonSerializable(typeof(OobeStateFile))]
|
[JsonSerializable(typeof(OobeStateFile))]
|
||||||
[JsonSerializable(typeof(DataLocationConfig))]
|
[JsonSerializable(typeof(DataLocationConfig))]
|
||||||
[JsonSerializable(typeof(GitHubRelease))]
|
|
||||||
[JsonSerializable(typeof(GitHubAsset))]
|
|
||||||
[JsonSerializable(typeof(List<GitHubRelease>))]
|
|
||||||
[JsonSerializable(typeof(StartupAttemptRecord))]
|
[JsonSerializable(typeof(StartupAttemptRecord))]
|
||||||
[JsonSerializable(typeof(PrivacyConfig))]
|
[JsonSerializable(typeof(PrivacyConfig))]
|
||||||
[JsonSerializable(typeof(PrivacyAgreementState))]
|
[JsonSerializable(typeof(PrivacyAgreementState))]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Text.Json;
|
|||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Deployment;
|
||||||
|
|
||||||
internal sealed class DeploymentLocator
|
internal sealed class DeploymentLocator
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Deployment;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主程序发现选项
|
/// 主程序发现选项
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Deployment;
|
||||||
|
|
||||||
internal sealed record HostLaunchPlan(
|
internal sealed record HostLaunchPlan(
|
||||||
string HostPath,
|
string HostPath,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Deployment;
|
||||||
|
|
||||||
internal sealed class HostResolutionResult
|
internal sealed class HostResolutionResult
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Deployment;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 老版本检测器 - 检测 0.8.x 及更早的单应用模式安装
|
/// 老版本检测器 - 检测 0.8.x 及更早的单应用模式安装
|
||||||
9
LanMountainDesktop.Launcher/GlobalUsings.cs
Normal file
9
LanMountainDesktop.Launcher/GlobalUsings.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
global using LanMountainDesktop.Launcher.AirApp;
|
||||||
|
global using LanMountainDesktop.Launcher.Deployment;
|
||||||
|
global using LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
global using LanMountainDesktop.Launcher.Ipc;
|
||||||
|
global using LanMountainDesktop.Launcher.Oobe;
|
||||||
|
global using LanMountainDesktop.Launcher.Plugins;
|
||||||
|
global using LanMountainDesktop.Launcher.Startup;
|
||||||
|
global using LanMountainDesktop.Launcher.Update;
|
||||||
|
global using LanMountainDesktop.Launcher.Services;
|
||||||
@@ -2,7 +2,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal static class Commands
|
internal static class Commands
|
||||||
{
|
{
|
||||||
@@ -171,16 +171,12 @@ internal static class Commands
|
|||||||
? launcherDir
|
? launcherDir
|
||||||
: AppContext.BaseDirectory);
|
: AppContext.BaseDirectory);
|
||||||
|
|
||||||
// 发布版结构:Launcher 和 app-* 目录在同一目录
|
|
||||||
// 检查当前目录是否有 app-* 子目录(发布版)
|
|
||||||
var appDirs = Directory.GetDirectories(baseDir, "app-*", SearchOption.TopDirectoryOnly);
|
var appDirs = Directory.GetDirectories(baseDir, "app-*", SearchOption.TopDirectoryOnly);
|
||||||
if (appDirs.Length > 0)
|
if (appDirs.Length > 0)
|
||||||
{
|
{
|
||||||
// 找到 app-* 目录,说明是发布版结构
|
|
||||||
return baseDir;
|
return baseDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开发环境:检查父目录是否有主程序
|
|
||||||
var parent = Path.GetFullPath(Path.Combine(baseDir, ".."));
|
var parent = Path.GetFullPath(Path.Combine(baseDir, ".."));
|
||||||
var parentHost = OperatingSystem.IsWindows()
|
var parentHost = OperatingSystem.IsWindows()
|
||||||
? Path.Combine(parent, "LanMountainDesktop.exe")
|
? Path.Combine(parent, "LanMountainDesktop.exe")
|
||||||
@@ -190,7 +186,6 @@ internal static class Commands
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认返回 baseDir
|
|
||||||
return baseDir;
|
return baseDir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析应用数据目录位置。
|
/// 解析应用数据目录位置。
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal sealed class DeferredSplashStageReporter : ISplashStageReporter
|
internal sealed class DeferredSplashStageReporter : ISplashStageReporter
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal enum DotNetRuntimeArchitecture
|
internal enum DotNetRuntimeArchitecture
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal interface ISplashStageReporter
|
internal interface ISplashStageReporter
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal static class LanguagePreferenceService
|
internal static class LanguagePreferenceService
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动器背景图片服务
|
/// 启动器背景图片服务
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal sealed record LauncherDebugSettings(bool DevModeEnabled, string? CustomHostPath);
|
internal sealed record LauncherDebugSettings(bool DevModeEnabled, string? CustomHostPath);
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
internal static class LauncherExecutionContext
|
internal static class LauncherExecutionContext
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 简单的日志记录器 - 同时输出到控制台和文件
|
/// 简单的日志记录器 - 同时输出到控制台和文件
|
||||||
@@ -2,7 +2,7 @@ using Avalonia;
|
|||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using FluentAvalonia.Styling;
|
using FluentAvalonia.Styling;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主题服务,管理启动器的主题设置
|
/// 主题服务,管理启动器的主题设置
|
||||||
@@ -3,7 +3,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.Ipc;
|
namespace LanMountainDesktop.Launcher.Ipc;
|
||||||
|
|
||||||
internal sealed class LauncherCoordinatorIpcClient
|
internal sealed class LauncherCoordinatorIpcClient
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.Text.Json;
|
|||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.Ipc;
|
namespace LanMountainDesktop.Launcher.Ipc;
|
||||||
|
|
||||||
internal sealed class LauncherCoordinatorIpcServer : IDisposable
|
internal sealed class LauncherCoordinatorIpcServer : IDisposable
|
||||||
{
|
{
|
||||||
@@ -2,10 +2,9 @@ using System.Buffers;
|
|||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
using LanMountainDesktop.Shared.Contracts.Update;
|
using LanMountainDesktop.Shared.Contracts.Update;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services.Ipc;
|
namespace LanMountainDesktop.Launcher.Ipc;
|
||||||
|
|
||||||
internal sealed class LauncherUpdateProgressIpcServer : IUpdateProgressReporter, IDisposable
|
internal sealed class LauncherUpdateProgressIpcServer : IUpdateProgressReporter, IDisposable
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- 只引用 Shared.Contracts(IPC 协议) -->
|
<!-- 只引用 Shared.Contracts(IPC 协议) -->
|
||||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||||
|
<ProjectReference Include="..\LanMountainDesktop.PluginPackaging\LanMountainDesktop.PluginPackaging.csproj" />
|
||||||
<ProjectReference Include="..\LanMountainDesktop.Shared.IPC\LanMountainDesktop.Shared.IPC.csproj" />
|
<ProjectReference Include="..\LanMountainDesktop.Shared.IPC\LanMountainDesktop.Shared.IPC.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Avalonia.Threading;
|
|||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
internal sealed class DataLocationOobeStep : IOobeStep
|
internal sealed class DataLocationOobeStep : IOobeStep
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System.Text.Json;
|
|||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在 OOBE 中向 Host 的 settings.json 写入启动与展示相关字段,属性名与 Host
|
/// 在 OOBE 中向 Host 的 settings.json 写入启动与展示相关字段,属性名与 Host
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
internal interface IOobeStep
|
internal interface IOobeStep
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将当前 Windows 用户登录时自启动项指向<strong>本 Launcher 进程</strong>(与正式入口一致)。
|
/// 将当前 Windows 用户登录时自启动项指向<strong>本 Launcher 进程</strong>(与正式入口一致)。
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
internal sealed class OobeStateService
|
internal sealed class OobeStateService
|
||||||
{
|
{
|
||||||
@@ -3,7 +3,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 隐私协议同意状态管理服务(带防篡改保护)
|
/// 隐私协议同意状态管理服务(带防篡改保护)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Oobe;
|
||||||
|
|
||||||
internal sealed class WelcomeOobeStep : IOobeStep
|
internal sealed class WelcomeOobeStep : IOobeStep
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System.IO.Compression;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Plugins;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 插件安装服务 - 简化版,不依赖 PluginSdk
|
/// 插件安装服务 - 简化版,不依赖 PluginSdk
|
||||||
@@ -290,7 +290,7 @@ internal sealed class PluginInstallerService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 简化的插件清单模型
|
/// 简化的插件清单模型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PluginManifest
|
internal class PluginManifest
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = "";
|
public string Id { get; set; } = "";
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Plugins;
|
||||||
|
|
||||||
internal sealed class PluginUpgradeQueueService
|
internal sealed class PluginUpgradeQueueService
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,7 @@ internal sealed class PluginUpgradeQueueService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var text = File.ReadAllText(pendingPath);
|
var text = File.ReadAllText(pendingPath);
|
||||||
var pending = JsonSerializer.Deserialize(text, AppJsonContext.Default.ListPendingUpgrade) ?? [];
|
var pending = JsonSerializer.Deserialize<List<PendingUpgrade>>(text, AppJsonContext.Default.Options) ?? [];
|
||||||
var failures = new List<string>();
|
var failures = new List<string>();
|
||||||
var succeeded = new List<PendingUpgrade>();
|
var succeeded = new List<PendingUpgrade>();
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ internal sealed class PluginUpgradeQueueService
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
File.WriteAllText(pendingPath, JsonSerializer.Serialize(remaining, AppJsonContext.Default.ListPendingUpgrade));
|
File.WriteAllText(pendingPath, JsonSerializer.Serialize(remaining, AppJsonContext.Default.Options));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LauncherResult
|
return new LauncherResult
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher;
|
namespace LanMountainDesktop.Launcher;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Diagnostics;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Resources;
|
using LanMountainDesktop.Launcher.Resources;
|
||||||
using LanMountainDesktop.Launcher.Services.Ipc;
|
|
||||||
using LanMountainDesktop.Launcher.Startup;
|
using LanMountainDesktop.Launcher.Startup;
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
@@ -185,115 +184,18 @@ internal sealed partial class LauncherFlowCoordinator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<PublicShellStatus?> TryGetPublicShellStatusAsync(
|
||||||
|
LanMountainDesktopIpcClient ipcClient) =>
|
||||||
|
await HostStartupMonitor.TryGetPublicShellStatusAsync(ipcClient).ConfigureAwait(false);
|
||||||
|
|
||||||
private static async Task<StartupSuccessState?> TryRecoverActivationThroughExistingHostAsync(
|
private static async Task<StartupSuccessState?> TryRecoverActivationThroughExistingHostAsync(
|
||||||
LanMountainDesktopIpcClient ipcClient,
|
LanMountainDesktopIpcClient ipcClient,
|
||||||
StartupSuccessTracker startupSuccessTracker,
|
StartupSuccessTracker startupSuccessTracker,
|
||||||
TimeSpan timeout)
|
TimeSpan timeout) =>
|
||||||
{
|
await HostStartupMonitor.TryRecoverActivationThroughExistingHostAsync(
|
||||||
var activation = await TryActivateExistingHostWithStatusAsync(ipcClient, timeout).ConfigureAwait(false);
|
ipcClient,
|
||||||
if (activation is null)
|
startupSuccessTracker,
|
||||||
{
|
timeout).ConfigureAwait(false);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startupSuccessTracker.TryResolve(activation.Status, out var shellSuccess))
|
|
||||||
{
|
|
||||||
return shellSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activation.Accepted)
|
|
||||||
{
|
|
||||||
return startupSuccessTracker.BuildRecoverySuccessState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return HostActivationPolicy.IsRecoverableActivationFailure(activation)
|
|
||||||
? new StartupSuccessState(
|
|
||||||
StartupStage.Ready,
|
|
||||||
"startup_pending",
|
|
||||||
activation.Message)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<PublicShellStatus?> TryGetPublicShellStatusAsync(
|
|
||||||
LanMountainDesktopIpcClient ipcClient)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var shellProxy = ipcClient.CreateProxy<IPublicShellControlService>();
|
|
||||||
return await shellProxy.GetShellStatusAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Warn($"Failed to query public shell status: {ex.Message}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<StartupSuccessState?> TryRecoverWithPublicActivationAsync(
|
|
||||||
LanMountainDesktopIpcClient ipcClient,
|
|
||||||
Process hostProcess,
|
|
||||||
Task<StartupSuccessState> successTask,
|
|
||||||
StartupSuccessTracker startupSuccessTracker)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var shellProxy = ipcClient.CreateProxy<IPublicShellControlService>();
|
|
||||||
var activation = await shellProxy.ActivateMainWindowWithStatusAsync().ConfigureAwait(false);
|
|
||||||
StartupDiagnostics.TraceShellStatus("recovery_activation", activation.Status);
|
|
||||||
if (startupSuccessTracker.TryResolve(activation.Status, out var shellSuccess))
|
|
||||||
{
|
|
||||||
return shellSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
var completedTask = await Task.WhenAny(successTask, Task.Delay(TimeSpan.FromSeconds(5))).ConfigureAwait(false);
|
|
||||||
if (completedTask == successTask)
|
|
||||||
{
|
|
||||||
return await successTask.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hostProcess.HasExited && (activation.Accepted || HostActivationPolicy.IsRecoverableActivationFailure(activation)))
|
|
||||||
{
|
|
||||||
return startupSuccessTracker.BuildRecoverySuccessState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Warn($"Public activation recovery failed: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LoadingStateMessage BuildDelayedLoadingState(
|
|
||||||
LoadingStateMessage loadingState,
|
|
||||||
string summaryMessage,
|
|
||||||
string detailMessage,
|
|
||||||
DateTimeOffset startedAtUtc)
|
|
||||||
{
|
|
||||||
var delayedItems = loadingState.ActiveItems
|
|
||||||
.Where(item => !string.Equals(item.Id, "launcher-soft-timeout", StringComparison.OrdinalIgnoreCase))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
delayedItems.Insert(0, new LoadingItem
|
|
||||||
{
|
|
||||||
Id = "launcher-soft-timeout",
|
|
||||||
Type = LoadingItemType.System,
|
|
||||||
Name = "Startup still in progress",
|
|
||||||
Description = detailMessage,
|
|
||||||
State = LoadingState.Delayed,
|
|
||||||
ProgressPercent = Math.Max(loadingState.OverallProgressPercent, 1),
|
|
||||||
Message = detailMessage,
|
|
||||||
StartTime = startedAtUtc
|
|
||||||
});
|
|
||||||
|
|
||||||
return loadingState with
|
|
||||||
{
|
|
||||||
ActiveItems = delayedItems,
|
|
||||||
Message = summaryMessage,
|
|
||||||
Timestamp = DateTimeOffset.UtcNow,
|
|
||||||
TotalCount = Math.Max(loadingState.TotalCount, delayedItems.Count)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, string> BuildAttemptDetails(
|
private static Dictionary<string, string> BuildAttemptDetails(
|
||||||
StartupAttemptRecord? trackedAttempt,
|
StartupAttemptRecord? trackedAttempt,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Diagnostics;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Resources;
|
using LanMountainDesktop.Launcher.Resources;
|
||||||
using LanMountainDesktop.Launcher.Services.Ipc;
|
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC;
|
using LanMountainDesktop.Shared.IPC;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Diagnostics;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Resources;
|
using LanMountainDesktop.Launcher.Resources;
|
||||||
using LanMountainDesktop.Launcher.Services.Ipc;
|
|
||||||
using LanMountainDesktop.Launcher.Startup;
|
using LanMountainDesktop.Launcher.Startup;
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
@@ -340,7 +339,7 @@ internal sealed partial class LauncherFlowCoordinator
|
|||||||
{
|
{
|
||||||
softTimeoutShown = true;
|
softTimeoutShown = true;
|
||||||
reporter.Report("delayed", SoftTimeoutStatusMessage);
|
reporter.Report("delayed", SoftTimeoutStatusMessage);
|
||||||
loadingState = BuildDelayedLoadingState(
|
loadingState = HostStartupMonitor.BuildDelayedLoadingState(
|
||||||
loadingState,
|
loadingState,
|
||||||
SoftTimeoutStatusMessage,
|
SoftTimeoutStatusMessage,
|
||||||
SoftTimeoutDetailsMessage,
|
SoftTimeoutDetailsMessage,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Launcher.Resources;
|
using LanMountainDesktop.Launcher.Resources;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
using LanMountainDesktop.Launcher.Views;
|
using LanMountainDesktop.Launcher.Views;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC;
|
using LanMountainDesktop.Shared.IPC;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
using LanMountainDesktop.Shared.IPC;
|
using LanMountainDesktop.Shared.IPC;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Startup;
|
namespace LanMountainDesktop.Launcher.Startup;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Text.Json;
|
|||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Startup;
|
||||||
|
|
||||||
internal sealed class StartupAttemptRegistry
|
internal sealed class StartupAttemptRegistry
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using LanMountainDesktop.Launcher.Services;
|
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using LanMountainDesktop.Shared.Contracts.Update;
|
using LanMountainDesktop.Shared.Contracts.Update;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Update;
|
||||||
|
|
||||||
public interface IUpdateProgressReporter
|
public interface IUpdateProgressReporter
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using LanMountainDesktop.Shared.Contracts.Update;
|
using LanMountainDesktop.Shared.Contracts.Update;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Update;
|
||||||
|
|
||||||
internal sealed class NullUpdateProgressReporter : IUpdateProgressReporter
|
internal sealed class NullUpdateProgressReporter : IUpdateProgressReporter
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.Text.Json;
|
|||||||
using LanMountainDesktop.Launcher.Models;
|
using LanMountainDesktop.Launcher.Models;
|
||||||
using ContractsUpdate = LanMountainDesktop.Shared.Contracts.Update;
|
using ContractsUpdate = LanMountainDesktop.Shared.Contracts.Update;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Services;
|
namespace LanMountainDesktop.Launcher.Update;
|
||||||
|
|
||||||
internal sealed class UpdateEngineService
|
internal sealed class UpdateEngineService
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,7 @@ public partial class OobeWindow : Window
|
|||||||
private bool _migrateExistingData;
|
private bool _migrateExistingData;
|
||||||
|
|
||||||
// 主题选择
|
// 主题选择
|
||||||
private Services.ThemeMode _selectedThemeMode = Services.ThemeMode.Light;
|
private ThemeMode _selectedThemeMode = ThemeMode.Light;
|
||||||
private string _selectedAccentColor = "#0078D4";
|
private string _selectedAccentColor = "#0078D4";
|
||||||
private MonetSource _selectedMonetSource = MonetSource.Wallpaper;
|
private MonetSource _selectedMonetSource = MonetSource.Wallpaper;
|
||||||
|
|
||||||
@@ -82,19 +82,19 @@ public partial class OobeWindow : Window
|
|||||||
// 浅色/深色模式选择
|
// 浅色/深色模式选择
|
||||||
if (this.FindControl<Border>("LightModeOption") is { } lightModeOption)
|
if (this.FindControl<Border>("LightModeOption") is { } lightModeOption)
|
||||||
{
|
{
|
||||||
lightModeOption.PointerPressed += (s, e) => SelectThemeMode(Services.ThemeMode.Light);
|
lightModeOption.PointerPressed += (s, e) => SelectThemeMode(ThemeMode.Light);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.FindControl<Border>("DarkModeOption") is { } darkModeOption)
|
if (this.FindControl<Border>("DarkModeOption") is { } darkModeOption)
|
||||||
{
|
{
|
||||||
darkModeOption.PointerPressed += (s, e) => SelectThemeMode(Services.ThemeMode.Dark);
|
darkModeOption.PointerPressed += (s, e) => SelectThemeMode(ThemeMode.Dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.FindControl<RadioButton>("LightModeRadio") is { } lightModeRadio)
|
if (this.FindControl<RadioButton>("LightModeRadio") is { } lightModeRadio)
|
||||||
{
|
{
|
||||||
lightModeRadio.IsCheckedChanged += (s, e) =>
|
lightModeRadio.IsCheckedChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
if (lightModeRadio.IsChecked == true) SelectThemeMode(Services.ThemeMode.Light);
|
if (lightModeRadio.IsChecked == true) SelectThemeMode(ThemeMode.Light);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public partial class OobeWindow : Window
|
|||||||
{
|
{
|
||||||
darkModeRadio.IsCheckedChanged += (s, e) =>
|
darkModeRadio.IsCheckedChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
if (darkModeRadio.IsChecked == true) SelectThemeMode(Services.ThemeMode.Dark);
|
if (darkModeRadio.IsChecked == true) SelectThemeMode(ThemeMode.Dark);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,7 +812,7 @@ public partial class OobeWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 主题选择方法
|
// 主题选择方法
|
||||||
private void SelectThemeMode(Services.ThemeMode mode)
|
private void SelectThemeMode(ThemeMode mode)
|
||||||
{
|
{
|
||||||
_selectedThemeMode = mode;
|
_selectedThemeMode = mode;
|
||||||
|
|
||||||
@@ -821,30 +821,30 @@ public partial class OobeWindow : Window
|
|||||||
|
|
||||||
if (this.FindControl<RadioButton>("LightModeRadio") is { } lightModeRadio)
|
if (this.FindControl<RadioButton>("LightModeRadio") is { } lightModeRadio)
|
||||||
{
|
{
|
||||||
lightModeRadio.IsChecked = mode == Services.ThemeMode.Light;
|
lightModeRadio.IsChecked = mode == ThemeMode.Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.FindControl<RadioButton>("DarkModeRadio") is { } darkModeRadio)
|
if (this.FindControl<RadioButton>("DarkModeRadio") is { } darkModeRadio)
|
||||||
{
|
{
|
||||||
darkModeRadio.IsChecked = mode == Services.ThemeMode.Dark;
|
darkModeRadio.IsChecked = mode == ThemeMode.Dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.FindControl<Border>("LightModeOption") is { } lightModeOption)
|
if (this.FindControl<Border>("LightModeOption") is { } lightModeOption)
|
||||||
{
|
{
|
||||||
lightModeOption.BorderBrush = mode == Services.ThemeMode.Light
|
lightModeOption.BorderBrush = mode == ThemeMode.Light
|
||||||
? Application.Current?.Resources["AccentFillColorDefaultBrush"] as IBrush
|
? Application.Current?.Resources["AccentFillColorDefaultBrush"] as IBrush
|
||||||
: Application.Current?.Resources["CardStrokeColorDefaultBrush"] as IBrush;
|
: Application.Current?.Resources["CardStrokeColorDefaultBrush"] as IBrush;
|
||||||
lightModeOption.BorderThickness = mode == Services.ThemeMode.Light
|
lightModeOption.BorderThickness = mode == ThemeMode.Light
|
||||||
? new Thickness(2)
|
? new Thickness(2)
|
||||||
: new Thickness(1);
|
: new Thickness(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.FindControl<Border>("DarkModeOption") is { } darkModeOption)
|
if (this.FindControl<Border>("DarkModeOption") is { } darkModeOption)
|
||||||
{
|
{
|
||||||
darkModeOption.BorderBrush = mode == Services.ThemeMode.Dark
|
darkModeOption.BorderBrush = mode == ThemeMode.Dark
|
||||||
? Application.Current?.Resources["AccentFillColorDefaultBrush"] as IBrush
|
? Application.Current?.Resources["AccentFillColorDefaultBrush"] as IBrush
|
||||||
: Application.Current?.Resources["CardStrokeColorDefaultBrush"] as IBrush;
|
: Application.Current?.Resources["CardStrokeColorDefaultBrush"] as IBrush;
|
||||||
darkModeOption.BorderThickness = mode == Services.ThemeMode.Dark
|
darkModeOption.BorderThickness = mode == ThemeMode.Dark
|
||||||
? new Thickness(2)
|
? new Thickness(2)
|
||||||
: new Thickness(1);
|
: new Thickness(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using LanMountainDesktop.Launcher.Services;
|
using LanMountainDesktop.Launcher.AirApp;
|
||||||
using LanMountainDesktop.Launcher.Services.AirApp;
|
using LanMountainDesktop.Launcher.Infrastructure;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Tests;
|
namespace LanMountainDesktop.Tests;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public sealed class CornerRadiusStyleTests
|
|||||||
ThemeVariant: "Dark"));
|
ThemeVariant: "Dark"));
|
||||||
|
|
||||||
var context = new PluginDesktopComponentContext(
|
var context = new PluginDesktopComponentContext(
|
||||||
new PluginManifest("plugin.id", "Plugin Name", "plugin.dll"),
|
new LanMountainDesktop.PluginSdk.PluginManifest("plugin.id", "Plugin Name", "plugin.dll"),
|
||||||
"C:\\Plugins\\plugin.id",
|
"C:\\Plugins\\plugin.id",
|
||||||
"C:\\Data\\plugin.id",
|
"C:\\Data\\plugin.id",
|
||||||
new NullServiceProvider(),
|
new NullServiceProvider(),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using LanMountainDesktop.ComponentSystem;
|
using LanMountainDesktop.ComponentSystem;
|
||||||
using LanMountainDesktop.Launcher;
|
using LanMountainDesktop.Launcher;
|
||||||
using LanMountainDesktop.Launcher.Services.AirApp;
|
using LanMountainDesktop.Launcher.AirApp;
|
||||||
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|||||||
6
LanMountainDesktop.Tests/LauncherGlobalUsings.cs
Normal file
6
LanMountainDesktop.Tests/LauncherGlobalUsings.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
global using LanMountainDesktop.Launcher.AirApp;
|
||||||
|
global using LanMountainDesktop.Launcher.Deployment;
|
||||||
|
global using LanMountainDesktop.Launcher.Infrastructure;
|
||||||
|
global using LanMountainDesktop.Launcher.Ipc;
|
||||||
|
global using LanMountainDesktop.Launcher.Oobe;
|
||||||
|
global using LanMountainDesktop.Launcher.Update;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using LanMountainDesktop.Launcher.Services;
|
using LanMountainDesktop.Launcher.Plugins;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public sealed class PluginManifestRuntimeTests
|
|||||||
""";
|
""";
|
||||||
|
|
||||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||||
var manifest = PluginManifest.Load(stream, "plugin.json");
|
var manifest = LanMountainDesktop.PluginSdk.PluginManifest.Load(stream, "plugin.json");
|
||||||
|
|
||||||
Assert.NotNull(manifest.Runtime);
|
Assert.NotNull(manifest.Runtime);
|
||||||
Assert.Equal(PluginRuntimeModes.InProcess, manifest.Runtime!.Mode);
|
Assert.Equal(PluginRuntimeModes.InProcess, manifest.Runtime!.Mode);
|
||||||
@@ -40,7 +40,7 @@ public sealed class PluginManifestRuntimeTests
|
|||||||
""";
|
""";
|
||||||
|
|
||||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||||
var ex = Assert.Throws<InvalidOperationException>(() => PluginManifest.Load(stream, "plugin.json"));
|
var ex = Assert.Throws<InvalidOperationException>(() => LanMountainDesktop.PluginSdk.PluginManifest.Load(stream, "plugin.json"));
|
||||||
|
|
||||||
Assert.Contains("runtime.mode", ex.Message);
|
Assert.Contains("runtime.mode", ex.Message);
|
||||||
Assert.Contains("shared-worker", ex.Message);
|
Assert.Contains("shared-worker", ex.Message);
|
||||||
|
|||||||
Reference in New Issue
Block a user