From b6fde8188daf0a186c0e4577517fa3e048df1a88 Mon Sep 17 00:00:00 2001 From: lincube Date: Tue, 11 Aug 2026 23:03:55 +0800 Subject: [PATCH] =?UTF-8?q?feat.AirApp=E9=87=8D=E6=9E=84=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 6 +- AGENTS.md | 24 +- LanMountainDesktop.slnx | 5 +- README.md | 49 +- .../AirAppDevServer.cs | 0 .../AirAppPackager.cs | 0 .../AirAppPreviewer.cs | 0 .../LanMountainDesktop.AirAppDevServer.csproj | 0 .../Program.cs | 0 .../AirAppLaunchOptions.cs | 6 +- .../AirAppWindow.axaml.cs | 124 ++++ .../AirAppWindowLoader.cs | 130 +++++ .../AirAppLifecycleService.cs | 3 +- .../IAirAppProcessStarter.cs | 10 +- .../AirAppAppearanceContext.cs} | 14 +- .../AirAppAppearanceExtensions.cs} | 32 +- .../AirAppAppearanceHelper.cs} | 34 +- .../AirAppAppearanceSnapshot.cs} | 14 +- .../AirAppBase.cs | 9 +- .../AirAppCapabilityDeclaration.cs} | 6 +- .../AirAppComponentChromeContext.cs | 11 + .../AirAppComponentContext.cs} | 51 +- .../AirAppComponentEditorContext.cs} | 20 +- .../AirAppComponentEditorRegistration.cs} | 14 +- .../AirAppComponentOptions.cs} | 12 +- .../AirAppComponentRegistration.cs} | 32 +- .../AirAppComponentResizeMode.cs | 7 + .../AirAppCornerRadiusPreset.cs} | 4 +- .../AirAppCornerRadiusTokens.cs | 52 ++ .../AirAppEntranceAttribute.cs | 4 - .../AirAppHostPropertyKeys.cs} | 6 +- .../AirAppInstalledInfo.cs | 8 + .../AirAppIpcClient.cs} | 16 +- .../AirAppIpcClientOptions.cs | 17 + .../AirAppIpcConstants.cs} | 12 +- .../AirAppIpcDelegates.cs} | 6 +- .../AirAppIpcErrorCodes.cs} | 4 +- .../AirAppIpcRoutedNotifyIds.cs | 17 + .../AirAppIpcRoutes.cs} | 4 +- .../AirAppIpcServer.cs} | 8 +- .../AirAppIpcServerOptions.cs | 17 + .../AirAppIsolationJsonContext.cs | 40 ++ .../AirAppIsolationProtocolVersion.cs | 6 + .../AirAppLocalizer.cs} | 22 +- .../AirAppManifest.cs | 102 ++-- .../AirAppPackageInstallResult.cs | 6 + .../AirAppPublicIpcServiceDescriptor.cs} | 4 +- .../AirAppPublicIpcServiceRegistration.cs | 6 + .../AirAppRuntimeConfiguration.cs | 15 + .../AirAppRuntimeMode.cs} | 4 +- .../AirAppRuntimeModes.cs} | 26 +- .../AirAppSdkInfo.cs} | 9 +- .../AirAppServiceCollectionExtensions.cs} | 71 ++- .../AirAppServiceExportDescriptor.cs | 6 + .../AirAppServiceExportRegistration.cs} | 6 +- .../AirAppSettingOptionChoice.cs} | 6 +- .../AirAppSettingOptionDefinition.cs} | 14 +- .../AirAppSettingOptionType.cs} | 4 +- .../AirAppSettingsCategories.cs} | 12 +- .../AirAppSettingsPageBase.cs} | 4 +- .../AirAppSettingsPageCategory.cs | 14 + .../AirAppSettingsPageInfoAttribute.cs} | 12 +- .../AirAppSettingsScope.cs | 9 + .../AirAppSettingsSectionBuilder.cs} | 70 +-- .../AirAppSettingsSectionDefinition.cs} | 14 +- .../AirAppSettingsSectionRegistration.cs} | 16 +- .../AirAppSharedContractReference.cs} | 10 +- .../AirAppWidgetBase.cs | 0 .../AirAppWindowBase.cs | 0 .../AirAppWindowChromeMode.cs | 0 .../AirAppWindowDescriptor.cs | 0 .../AirAppWindowRegistration.cs | 11 + .../AirAppWorkerBase.cs} | 8 +- .../AirAppWorkerEntranceAttribute.cs | 6 + .../AppearanceChangedEvent.cs | 6 +- .../AppearanceContracts.cs | 14 +- .../AppearanceCornerRadiusTokenFactory.cs | 4 +- .../AssemblyInfo.cs | 2 +- .../DiagnosticsContracts.cs | 14 +- .../GlobalAppearanceSettings.cs | 2 +- .../LanMountainDesktop.AirAppSdk/IAirApp.cs | 5 +- .../IAirAppAppearanceContext.cs} | 8 +- .../IAirAppComponentContext.cs | 0 .../IAirAppExportRegistry.cs | 13 + .../IAirAppLogger.cs | 0 .../IAirAppMessageBus.cs | 13 +- .../IAirAppPackageManager.cs | 8 + .../IAirAppPublicIpcBuilder.cs} | 8 +- .../IAirAppPublicIpcContributor.cs | 6 + .../IAirAppRuntimeContext.cs | 36 +- .../IAirAppSettingsService.cs} | 6 +- .../IAirAppWidget.cs | 0 .../IAirAppWindow.cs | 7 + .../IAirAppWorker.cs} | 8 +- .../IAirAppWorkerContext.cs | 26 + .../IComponentEditorHostContext.cs | 2 +- .../IComponentSettingsAccessor.cs | 2 +- .../IDesktopShellHost.cs | 2 +- .../IHostApplicationLifecycle.cs | 2 +- .../ISettingsCatalog.cs | 10 + .../ISettingsPageHostContext.cs | 2 +- .../ISettingsService.cs | 16 +- .../InProcAirAppIpcTransport.cs} | 20 +- airapp/LanMountainDesktop.AirAppSdk/LICENSE | 21 + .../LanMountainDesktop.AirAppSdk.csproj} | 15 +- .../LifecycleContracts.cs | 16 +- airapp/LanMountainDesktop.AirAppSdk/README.md | 39 ++ .../SessionContracts.cs | 21 + .../SettingsChangedEvent.cs | 6 +- .../SettingsContracts.cs | 12 +- .../UiContracts.cs | 18 +- .../LanMountainDesktop.AirAppSdk.props | 14 + .../LanMountainDesktop.AirAppSdk.targets | 51 ++ .../LanMountainDesktop.AirAppTemplate.csproj} | 6 +- .../README.md | 0 .../content/.template.config/template.json | 90 +++ .../content/AirApp.cs | 44 ++ .../LanMountainDesktop.AirAppTemplate.csproj} | 6 +- .../content/Localization/en-US.json | 0 .../content/Localization/zh-CN.json | 0 .../content/MyComponent.cs | 35 ++ .../content/MyWindow.cs | 24 + .../content/README.md | 0 .../content/airapp.json | 27 + .../ComponentChromeContext.cs | 11 - .../LanMountainDesktop.PluginSdk/IPlugin.cs | 9 - .../IPluginContext.cs | 6 - .../IPluginExportRegistry.cs | 13 - .../IPluginMessageBus.cs | 8 - .../IPluginPackageManager.cs | 8 - .../IPluginPublicIpcContributor.cs | 6 - .../IPluginRuntimeContext.cs | 20 - .../IPluginWorkerContext.cs | 26 - .../ISettingsCatalog.cs | 10 - .../InstalledPluginInfo.cs | 8 - airapp/LanMountainDesktop.PluginSdk/LICENSE | 165 ------ .../PluginBase.cs | 11 - .../PluginCornerRadiusTokens.cs | 52 -- .../PluginDesktopComponentResizeMode.cs | 7 - .../PluginEntranceAttribute.cs | 6 - .../PluginIpcClientOptions.cs | 17 - .../PluginIpcRoutedNotifyIds.cs | 17 - .../PluginIpcServerOptions.cs | 17 - .../PluginIsolationJsonContext.cs | 40 -- .../PluginIsolationProtocolVersion.cs | 6 - .../PluginManifest.cs | 152 ----- .../PluginPackageInstallResult.cs | 6 - .../PluginPublicIpcServiceRegistration.cs | 6 - .../PluginRuntimeConfiguration.cs | 15 - .../PluginServiceExportDescriptor.cs | 6 - .../PluginWorkerEntranceAttribute.cs | 6 - airapp/LanMountainDesktop.PluginSdk/README.md | 23 - .../SessionContracts.cs | 21 - .../SettingsPageCategory.cs | 14 - .../SettingsScope.cs | 9 - .../LanMountainDesktop.PluginSdk.props | 14 - .../LanMountainDesktop.PluginSdk.targets | 51 -- .../content/.template.config/template.json | 55 -- .../content/Plugin.cs | 47 -- .../content/plugin.json | 13 - .../AirAppAppearanceSnapshot.cs | 49 -- .../AirAppComponentOptions.cs | 61 -- .../AirAppComponentResizeMode.cs | 27 - .../AirAppCornerRadiusPreset.cs | 32 -- .../AirAppRuntimeMode.cs | 53 -- .../AirAppSdkInfo.cs | 33 -- .../AirAppServiceCollectionExtensions.cs | 158 ----- .../IAirAppAppearanceContext.cs | 19 - .../LanMountainDesktop.AirAppSdk.csproj | 33 -- .../LanMountainDesktop.AirAppSdk/README.md | 363 ------------ .../LanMountainDesktop.AirAppTemplate.csproj | 22 - .../component/.template.config/template.json | 37 -- ...ainDesktop.AirApp.ComponentTemplate.csproj | 19 - .../templates/component/MyAirApp.cs | 40 -- .../templates/component/MyWidget.cs | 81 --- .../templates/component/README.md | 28 - .../templates/component/airapp.json | 21 - .../Services/IAirAppLifecycleService.cs | 3 +- .../Launcher/LauncherIpc.cs | 2 +- .../Launcher/LoadingState.cs | 2 +- .../PendingPluginUpgradeStore.cs | 2 +- .../PluginPackageInstallOptions.cs | 2 +- .../PluginPackageInstallResult.cs | 2 +- .../PluginPackageInstaller.cs | 2 +- .../PluginPackageManifest.cs | 2 +- .../PluginPackageManifestReader.cs | 2 +- .../PluginPackagingConstants.cs | 4 +- .../AirAppInstallerService.cs} | 46 +- .../AirAppUpgradeQueueService.cs} | 18 +- .../AppJsonContext.cs | 4 +- .../CommandContext.cs | 4 +- .../GlobalUsings.cs | 2 +- .../Infrastructure/Commands.cs | 18 +- .../LanMountainDesktop.Launcher/Program.cs | 6 +- .../Resources/Strings.cs | 8 +- .../EntryHandlers/PreviewEntryHandler.cs | 2 +- .../Shell/LaunchUiPresenter.cs | 2 +- .../Views/DevDebugWindow.axaml.cs | 2 +- .../Views/LoadingDetailsWindow.axaml.cs | 12 +- .../AirAppCatalogEntry.cs} | 12 +- .../AirApps/AirAppContributions.cs | 16 + .../AirAppExportRegistry.cs} | 28 +- .../AirAppLoadContext.cs} | 10 +- .../AirApps/AirAppLoadResult.cs | 24 + .../AirAppLoader.cs} | 527 +++++++++++------ .../AirApps/AirAppLoaderOptions.cs | 28 + .../AirAppMarketAssetCacheService.cs} | 14 +- .../AirAppMarketCacheService.cs} | 2 +- .../AirAppMarketIconService.cs} | 10 +- .../AirAppMarketIndexService.cs} | 4 +- .../AirAppMarketInstallService.cs} | 110 ++-- .../AirAppMarketModels.cs} | 98 ++-- .../AirAppMarketReadmeService.cs} | 10 +- .../AirAppMarketReleaseResolverService.cs} | 20 +- .../AirAppRuntimeService.cs} | 538 +++++++++--------- .../AirAppScopedSettingsService.cs} | 26 +- .../AirAppSharedContractManager.cs} | 34 +- .../DevAirAppOptions.cs} | 26 +- .../LoadedAirApp.cs} | 62 +- .../{plugins => AirApps}/README.md | 0 desktop/LanMountainDesktop/App.axaml.cs | 42 +- .../DesktopComponentEditorRegistry.cs | 2 +- .../DesktopComponentRuntimeContext.cs | 6 +- .../IComponentChromeContextAware.cs | 6 +- .../IComponentSettingsContextAware.cs | 2 +- .../LanMountainDesktop/DesktopShellHost.cs | 10 +- ...lper.cs => AirAppCatalogMarkdownHelper.cs} | 2 +- .../LanMountainDesktop.csproj | 2 +- .../Models/AppSettingsSnapshot.cs | 2 +- desktop/LanMountainDesktop/Program.cs | 8 +- ...r.cs => AirAppAppearanceSnapshotMapper.cs} | 20 +- ...Access.cs => AirAppInstallTargetAccess.cs} | 2 +- .../Services/AirAppLauncherService.cs | 21 +- .../Services/AppDataPathProvider.cs | 4 +- .../Services/AppRestartService.cs | 2 +- .../Services/AppearanceThemeService.cs | 6 +- .../Services/ComponentEditorWindowService.cs | 2 +- .../Services/ComponentSettingsService.cs | 26 +- .../Services/DataStorageService.cs | 6 +- .../DesktopComponentEditorRegistryFactory.cs | 32 +- .../DesktopComponentRegistryFactory.cs | 83 +-- .../Services/DesktopTrayService.cs | 2 +- ...ice.cs => ElevatedAirAppInstallService.cs} | 30 +- .../ExternalIpc/PublicShellControlService.cs | 2 +- .../Services/FusedDesktopManagerService.cs | 10 +- .../HostApplicationLifecycleService.cs | 2 +- .../IComponentInstanceSettingsStore.cs | 6 +- .../Loading/LoadingStateUsageExample.cs | 8 +- .../Services/MaterialColorService.cs | 8 +- .../Services/NotificationListenerService.cs | 6 +- .../Services/NotificationService.cs | 6 +- ...vice.cs => PendingAirAppUpgradeService.cs} | 28 +- .../Services/PendingRestartStateService.cs | 2 +- .../Services/PostHogUsageTelemetryService.cs | 6 +- .../Services/SentryCrashTelemetryService.cs | 6 +- .../Settings/ComponentDomainStorage.cs | 8 +- .../Settings/HostSettingsFacadeProvider.cs | 4 +- .../Settings/SettingsCatalogService.cs | 44 +- .../Services/Settings/SettingsContracts.cs | 108 ++-- .../Settings/SettingsDomainServices.cs | 186 +++--- .../Services/Settings/SettingsPageRegistry.cs | 66 +-- .../Services/Settings/SettingsService.cs | 104 ++-- .../SettingsServiceAppSnapshotExtensions.cs | 6 +- .../Settings/SettingsWindowService.cs | 6 +- .../Services/SettingsSearchService.cs | 2 +- .../Services/TelemetryEventNames.cs | 16 +- .../Services/TelemetryIdentityService.cs | 10 +- ...=> AirAppCatalogSettingsPageViewModels.cs} | 166 +++--- .../LauncherSettingsPageViewModel.cs | 8 +- .../ViewModels/MusicControlViewModel.cs | 2 +- .../NotificationSettingsPageViewModel.cs | 8 +- .../ViewModels/PrivacyPolicyViewModel.cs | 2 +- .../PrivacySettingsPageViewModel.cs | 2 +- .../ViewModels/SettingsViewModels.cs | 152 ++--- .../Components/AnalogClockWidget.axaml.cs | 6 +- .../Components/BaiduHotSearchWidget.axaml.cs | 2 +- .../BilibiliHotSearchWidget.axaml.cs | 2 +- .../Components/ClassScheduleWidget.axaml.cs | 6 +- .../Components/CnrDailyNewsWidget.axaml.cs | 2 +- .../ComponentChromeCornerRadiusHelper.cs | 26 +- .../Components/DailyArtworkWidget.axaml.cs | 6 +- .../Components/DailyPoetryWidget.axaml.cs | 2 +- .../Components/DailyWord2x2Widget.axaml.cs | 2 +- .../Views/Components/DailyWordWidget.axaml.cs | 2 +- .../DesktopComponentRuntimeRegistry.cs | 28 +- .../ExchangeRateCalculatorWidget.axaml.cs | 2 +- .../Components/FileManagerWidget.axaml.cs | 2 +- .../Views/Components/IfengNewsWidget.axaml.cs | 2 +- .../Components/NotificationBoxWidget.axaml.cs | 4 +- .../Views/Components/RecordingWidget.axaml.cs | 2 +- .../RemovableStorageWidget.axaml.cs | 4 +- .../Views/Components/RssReaderWidget.axaml.cs | 2 +- .../Views/Components/ShortcutWidget.axaml.cs | 2 +- .../StandbyDigitalClockWidget.axaml.cs | 6 +- .../Components/Stcn24ForumWidget.axaml.cs | 2 +- .../Components/StickyNoteWidget.axaml.cs | 10 +- .../StudyDeductionReasonsWidget.axaml.cs | 2 +- .../StudyEnvironmentWidget.axaml.cs | 2 +- .../StudyInterruptDensityWidget.axaml.cs | 2 +- .../Components/StudyNoiseCurveWidget.axaml.cs | 2 +- .../StudyNoiseDistributionWidget.axaml.cs | 2 +- .../StudyScoreOverviewWidget.axaml.cs | 2 +- .../StudySessionControlWidget.axaml.cs | 2 +- .../StudySessionHistoryWidget.axaml.cs | 2 +- .../Views/Components/WeatherWidgetBase.cs | 12 +- .../Components/WorldClockWidget.axaml.cs | 2 +- .../Components/ZhiJiaoHubWidget.axaml.cs | 2 +- ...sedDesktopComponentLibraryControl.axaml.cs | 2 +- ...usedDesktopComponentLibraryWindow.axaml.cs | 4 +- .../Views/MainWindow.ComponentSystem.cs | 6 +- .../Views/MainWindow.DesktopPaging.cs | 4 +- .../Views/MainWindow.SettingsHardCut.Stubs.cs | 22 +- .../Views/MainWindow.axaml.cs | 12 +- .../SettingsPages/AboutSettingsPage.axaml.cs | 14 +- ....axaml => AirAppCatalogDetailDrawer.axaml} | 6 +- ....cs => AirAppCatalogDetailDrawer.axaml.cs} | 6 +- ....axaml => AirAppCatalogSettingsPage.axaml} | 8 +- ....cs => AirAppCatalogSettingsPage.axaml.cs} | 76 +-- ...xaml => AirAppGeneratedSettingsPage.axaml} | 4 +- ...s => AirAppGeneratedSettingsPage.axaml.cs} | 158 ++--- ...gsPage.axaml => AirAppsSettingsPage.axaml} | 12 +- ....axaml.cs => AirAppsSettingsPage.axaml.cs} | 34 +- .../AppearanceSettingsPage.axaml.cs | 8 +- .../ComponentsSettingsPage.axaml.cs | 8 +- .../SettingsPages/DataSettingsPage.axaml.cs | 8 +- .../Views/SettingsPages/DevSettingsPage.axaml | 8 +- .../SettingsPages/DevSettingsPage.axaml.cs | 8 +- .../GeneralSettingsPage.axaml.cs | 8 +- .../LauncherSettingsPage.axaml.cs | 10 +- .../MaterialColorSettingsPage.axaml.cs | 8 +- .../NotificationSettingsPage.axaml.cs | 8 +- .../SettingsPages/PrivacyPolicyDrawer.axaml | 2 +- .../PrivacySettingsPage.axaml.cs | 8 +- .../StatusBarSettingsPage.axaml.cs | 8 +- .../SettingsPages/StudySettingsPage.axaml.cs | 8 +- .../SettingsPages/UpdateSettingsPage.axaml.cs | 8 +- .../WallpaperSettingsPage.axaml.cs | 8 +- .../WeatherSettingsPage.axaml.cs | 8 +- .../Views/SettingsWindow.axaml.cs | 16 +- .../plugins/PluginContributions.cs | 16 - .../plugins/PluginLoadResult.cs | 24 - .../plugins/PluginLoaderOptions.cs | 28 - docs/00-快速开始/01-项目介绍.md | 28 +- docs/00-快速开始/02-快速安装.md | 8 +- docs/00-快速开始/03-开发环境配置.md | 26 +- .../01-快速开始/01-环境准备.md | 138 ++--- .../01-快速开始/02-创建第一个轻应用.md} | 144 ++--- .../02-核心概念/01-轻应用生命周期.md} | 164 +++--- .../02-核心概念/02-组件系统.md | 24 +- .../02-核心概念/03-设置系统.md | 60 +- .../03-API参考/01-IAirApp接口.md} | 152 ++--- .../03-API参考/02-IAirAppRuntimeContext.md} | 118 ++-- docs/{01-插件开发 => 01-AirApp开发}/README.md | 106 ++-- docs/02-AirApp开发/README.md | 109 ++-- docs/03-组件设计规范/02-视觉规范.md | 4 +- docs/03-组件设计规范/03-布局规范.md | 4 +- docs/03-组件设计规范/04-交互规范.md | 2 +- docs/03-组件设计规范/05-主题系统.md | 10 +- docs/03-组件设计规范/DESIGN_SPEC_REPORT.md | 4 +- docs/03-组件设计规范/README.md | 6 +- docs/04-架构与实现/01-整体架构.md | 54 +- docs/05-更新与发布/01-更新系统架构.md | 2 +- docs/AIRAPP_SDK_V1_MIGRATION.md | 110 ++++ docs/README.md | 36 +- .../LanMountainDesktop.Mobile.csproj | 2 +- scripts/Pack-PluginPackages.ps1 | 6 +- scripts/Publish-Plonds.ps1 | 2 +- ...ts.cs => AirAppAppearanceBoundaryTests.cs} | 54 +- ...ests.cs => AirAppInstallerServiceTests.cs} | 48 +- ...Tests.cs => AirAppManifestRuntimeTests.cs} | 16 +- ...s.cs => AirAppMarketCompatibilityTests.cs} | 32 +- ...s.cs => AirAppMarketIndexDocumentTests.cs} | 46 +- ...Tests.cs => AirAppRuntimeDataPathTests.cs} | 12 +- .../AirAppRuntimeLifecycleServiceTests.cs | 3 +- .../AirAppSdkVersionConsistencyTests.cs | 33 ++ .../AppearanceSettingsPageViewModelTests.cs | 8 +- ...tInDesktopHostCornerRadiusBaselineTests.cs | 8 +- .../ComponentSettingsServiceTests.cs | 18 +- .../CornerRadiusStyleTests.cs | 30 +- ...entRuntimeRegistrationCornerRadiusTests.cs | 10 +- .../ExternalIpcPublicApiTests.cs | 16 +- .../FusedDesktopLibraryMetadataTests.cs | 16 +- .../LanMountainDesktop.Tests/GlobalUsings.cs | 2 +- ...ts.cs => InProcAirAppIpcTransportTests.cs} | 22 +- ...InfoRecommendationHostCornerRadiusTests.cs | 8 +- .../LanMountainDesktop.Tests.csproj | 2 +- .../MaterialColorIntegrationTests.cs | 4 +- ...MaterialColorSettingsPageViewModelTests.cs | 10 +- .../NotificationListenerServiceTests.cs | 16 +- ...cs => PendingAirAppUpgradeServiceTests.cs} | 60 +- .../SettingsCatalogServiceTests.cs | 12 +- .../SettingsSearchResultTests.cs | 2 +- .../UpdateSettingsInterfaceTests.cs | 20 +- .../WallpaperSettingsPageViewModelTests.cs | 8 +- 394 files changed, 4484 insertions(+), 5120 deletions(-) rename {airappsdk => airapp}/LanMountainDesktop.AirAppDevServer/AirAppDevServer.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppDevServer/AirAppPackager.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppDevServer/AirAppPreviewer.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppDevServer/LanMountainDesktop.AirAppDevServer.csproj (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppDevServer/Program.cs (100%) create mode 100644 airapp/LanMountainDesktop.AirAppHost/AirAppWindowLoader.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginAppearanceContext.cs => LanMountainDesktop.AirAppSdk/AirAppAppearanceContext.cs} (86%) rename airapp/{LanMountainDesktop.PluginSdk/PluginAppearanceExtensions.cs => LanMountainDesktop.AirAppSdk/AirAppAppearanceExtensions.cs} (74%) rename airapp/{LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs => LanMountainDesktop.AirAppSdk/AirAppAppearanceHelper.cs} (78%) rename airapp/{LanMountainDesktop.PluginSdk/PluginAppearanceSnapshot.cs => LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs} (67%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppBase.cs (94%) rename airapp/{LanMountainDesktop.PluginSdk/PluginCapabilityDeclaration.cs => LanMountainDesktop.AirAppSdk/AirAppCapabilityDeclaration.cs} (76%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppComponentChromeContext.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginDesktopComponentContext.cs => LanMountainDesktop.AirAppSdk/AirAppComponentContext.cs} (57%) rename airapp/{LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorContext.cs => LanMountainDesktop.AirAppSdk/AirAppComponentEditorContext.cs} (79%) rename airapp/{LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorRegistration.cs => LanMountainDesktop.AirAppSdk/AirAppComponentEditorRegistration.cs} (78%) rename airapp/{LanMountainDesktop.PluginSdk/PluginDesktopComponentOptions.cs => LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs} (57%) rename airapp/{LanMountainDesktop.PluginSdk/PluginDesktopComponentRegistration.cs => LanMountainDesktop.AirAppSdk/AirAppComponentRegistration.cs} (72%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginCornerRadiusPreset.cs => LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs} (62%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusTokens.cs rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs (54%) rename airapp/{LanMountainDesktop.PluginSdk/PluginHostPropertyKeys.cs => LanMountainDesktop.AirAppSdk/AirAppHostPropertyKeys.cs} (57%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppInstalledInfo.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcClient.cs => LanMountainDesktop.AirAppSdk/AirAppIpcClient.cs} (84%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClientOptions.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcConstants.cs => LanMountainDesktop.AirAppSdk/AirAppIpcConstants.cs} (75%) rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcDelegates.cs => LanMountainDesktop.AirAppSdk/AirAppIpcDelegates.cs} (54%) rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcErrorCodes.cs => LanMountainDesktop.AirAppSdk/AirAppIpcErrorCodes.cs} (86%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutedNotifyIds.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcRoutes.cs => LanMountainDesktop.AirAppSdk/AirAppIpcRoutes.cs} (94%) rename airapp/{LanMountainDesktop.PluginSdk/PluginIpcServer.cs => LanMountainDesktop.AirAppSdk/AirAppIpcServer.cs} (94%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServerOptions.cs create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationJsonContext.cs create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationProtocolVersion.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginLocalizer.cs => LanMountainDesktop.AirAppSdk/AirAppLocalizer.cs} (83%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppManifest.cs (70%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppPackageInstallResult.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginPublicIpcServiceDescriptor.cs => LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceDescriptor.cs} (50%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceRegistration.cs create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeConfiguration.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginRuntimeMode.cs => LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs} (51%) rename airapp/{LanMountainDesktop.PluginSdk/PluginRuntimeModes.cs => LanMountainDesktop.AirAppSdk/AirAppRuntimeModes.cs} (64%) rename airapp/{LanMountainDesktop.PluginSdk/PluginSdkInfo.cs => LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs} (57%) rename airapp/{LanMountainDesktop.PluginSdk/PluginServiceCollectionExtensions.cs => LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs} (68%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportDescriptor.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginServiceExportRegistration.cs => LanMountainDesktop.AirAppSdk/AirAppServiceExportRegistration.cs} (67%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsOptionChoice.cs => LanMountainDesktop.AirAppSdk/AirAppSettingOptionChoice.cs} (65%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsOptionDefinition.cs => LanMountainDesktop.AirAppSdk/AirAppSettingOptionDefinition.cs} (77%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsOptionType.cs => LanMountainDesktop.AirAppSdk/AirAppSettingOptionType.cs} (55%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsCategories.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsCategories.cs} (53%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsPageBase.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsPageBase.cs} (92%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageCategory.cs rename airapp/{LanMountainDesktop.PluginSdk/SettingsPageInfoAttribute.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsPageInfoAttribute.cs} (72%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsScope.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginSettingsSectionBuilder.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsSectionBuilder.cs} (65%) rename airapp/{LanMountainDesktop.PluginSdk/SettingsSectionDefinition.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsSectionDefinition.cs} (78%) rename airapp/{LanMountainDesktop.PluginSdk/PluginSettingsSectionRegistration.cs => LanMountainDesktop.AirAppSdk/AirAppSettingsSectionRegistration.cs} (77%) rename airapp/{LanMountainDesktop.PluginSdk/PluginSharedContractReference.cs => LanMountainDesktop.AirAppSdk/AirAppSharedContractReference.cs} (80%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppWidgetBase.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppWindowBase.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppWindowChromeMode.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/AirAppWindowDescriptor.cs (100%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppWindowRegistration.cs rename airapp/{LanMountainDesktop.PluginSdk/PluginWorkerBase.cs => LanMountainDesktop.AirAppSdk/AirAppWorkerBase.cs} (61%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerEntranceAttribute.cs rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/AppearanceChangedEvent.cs (93%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/AppearanceContracts.cs (72%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/AppearanceCornerRadiusTokenFactory.cs (96%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/AssemblyInfo.cs (80%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/DiagnosticsContracts.cs (78%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/GlobalAppearanceSettings.cs (98%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirApp.cs (79%) rename airapp/{LanMountainDesktop.PluginSdk/IPluginAppearanceContext.cs => LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs} (85%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppComponentContext.cs (100%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/IAirAppExportRegistry.cs rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppLogger.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs (71%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/IAirAppPackageManager.cs rename airapp/{LanMountainDesktop.PluginSdk/IPluginPublicIpcBuilder.cs => LanMountainDesktop.AirAppSdk/IAirAppPublicIpcBuilder.cs} (60%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcContributor.cs rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs (69%) rename airapp/{LanMountainDesktop.PluginSdk/IPluginSettingsService.cs => LanMountainDesktop.AirAppSdk/IAirAppSettingsService.cs} (82%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppWidget.cs (100%) rename {airappsdk => airapp}/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs (76%) rename airapp/{LanMountainDesktop.PluginSdk/IPluginWorker.cs => LanMountainDesktop.AirAppSdk/IAirAppWorker.cs} (50%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/IAirAppWorkerContext.cs rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/IComponentEditorHostContext.cs (79%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/IComponentSettingsAccessor.cs (93%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/IDesktopShellHost.cs (56%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/IHostApplicationLifecycle.cs (88%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/ISettingsCatalog.cs rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/ISettingsPageHostContext.cs (83%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/ISettingsService.cs (76%) rename airapp/{LanMountainDesktop.PluginSdk/InProcPluginIpcTransport.cs => LanMountainDesktop.AirAppSdk/InProcAirAppIpcTransport.cs} (75%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/LICENSE rename airapp/{LanMountainDesktop.PluginSdk/LanMountainDesktop.PluginSdk.csproj => LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj} (68%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/LifecycleContracts.cs (62%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/README.md create mode 100644 airapp/LanMountainDesktop.AirAppSdk/SessionContracts.cs rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/SettingsChangedEvent.cs (87%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/SettingsContracts.cs (64%) rename airapp/{LanMountainDesktop.PluginSdk => LanMountainDesktop.AirAppSdk}/UiContracts.cs (70%) create mode 100644 airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.props create mode 100644 airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.targets rename airapp/{LanMountainDesktop.PluginTemplate/LanMountainDesktop.PluginTemplate.csproj => LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj} (83%) rename airapp/{LanMountainDesktop.PluginTemplate => LanMountainDesktop.AirAppTemplate}/README.md (100%) create mode 100644 airapp/LanMountainDesktop.AirAppTemplate/content/.template.config/template.json create mode 100644 airapp/LanMountainDesktop.AirAppTemplate/content/AirApp.cs rename airapp/{LanMountainDesktop.PluginTemplate/content/LanMountainDesktop.PluginTemplate.csproj => LanMountainDesktop.AirAppTemplate/content/LanMountainDesktop.AirAppTemplate.csproj} (62%) rename airapp/{LanMountainDesktop.PluginTemplate => LanMountainDesktop.AirAppTemplate}/content/Localization/en-US.json (100%) rename airapp/{LanMountainDesktop.PluginTemplate => LanMountainDesktop.AirAppTemplate}/content/Localization/zh-CN.json (100%) create mode 100644 airapp/LanMountainDesktop.AirAppTemplate/content/MyComponent.cs create mode 100644 airapp/LanMountainDesktop.AirAppTemplate/content/MyWindow.cs rename airapp/{LanMountainDesktop.PluginTemplate => LanMountainDesktop.AirAppTemplate}/content/README.md (100%) create mode 100644 airapp/LanMountainDesktop.AirAppTemplate/content/airapp.json delete mode 100644 airapp/LanMountainDesktop.PluginSdk/ComponentChromeContext.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPlugin.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginContext.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginExportRegistry.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginMessageBus.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginPackageManager.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcContributor.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginRuntimeContext.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/IPluginWorkerContext.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/ISettingsCatalog.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/InstalledPluginInfo.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/LICENSE delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginBase.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusTokens.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentResizeMode.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginEntranceAttribute.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginIpcClientOptions.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutedNotifyIds.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginIpcServerOptions.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginIsolationJsonContext.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginIsolationProtocolVersion.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginManifest.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginPackageInstallResult.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceRegistration.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginRuntimeConfiguration.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginServiceExportDescriptor.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/PluginWorkerEntranceAttribute.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/README.md delete mode 100644 airapp/LanMountainDesktop.PluginSdk/SessionContracts.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/SettingsPageCategory.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/SettingsScope.cs delete mode 100644 airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.props delete mode 100644 airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.targets delete mode 100644 airapp/LanMountainDesktop.PluginTemplate/content/.template.config/template.json delete mode 100644 airapp/LanMountainDesktop.PluginTemplate/content/Plugin.cs delete mode 100644 airapp/LanMountainDesktop.PluginTemplate/content/plugin.json delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj delete mode 100644 airappsdk/LanMountainDesktop.AirAppSdk/README.md delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/.template.config/template.json delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/LanMountainDesktop.AirApp.ComponentTemplate.csproj delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyAirApp.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyWidget.cs delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/README.md delete mode 100644 airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/airapp.json rename desktop/LanMountainDesktop.Launcher/{Plugins/PluginInstallerService.cs => AirApps/AirAppInstallerService.cs} (87%) rename desktop/LanMountainDesktop.Launcher/{Plugins/PluginUpgradeQueueService.cs => AirApps/AirAppUpgradeQueueService.cs} (84%) rename desktop/LanMountainDesktop/{plugins/PluginCatalogEntry.cs => AirApps/AirAppCatalogEntry.cs} (55%) create mode 100644 desktop/LanMountainDesktop/AirApps/AirAppContributions.cs rename desktop/LanMountainDesktop/{plugins/PluginExportRegistry.cs => AirApps/AirAppExportRegistry.cs} (60%) rename desktop/LanMountainDesktop/{plugins/PluginLoadContext.cs => AirApps/AirAppLoadContext.cs} (89%) create mode 100644 desktop/LanMountainDesktop/AirApps/AirAppLoadResult.cs rename desktop/LanMountainDesktop/{plugins/PluginLoader.cs => AirApps/AirAppLoader.cs} (68%) create mode 100644 desktop/LanMountainDesktop/AirApps/AirAppLoaderOptions.cs rename desktop/LanMountainDesktop/{plugins/PluginMarketAssetCacheService.cs => AirApps/AirAppMarketAssetCacheService.cs} (96%) rename desktop/LanMountainDesktop/{plugins/PluginMarketCacheService.cs => AirApps/AirAppMarketCacheService.cs} (95%) rename desktop/LanMountainDesktop/{plugins/PluginMarketIconService.cs => AirApps/AirAppMarketIconService.cs} (90%) rename desktop/LanMountainDesktop/{plugins/PluginMarketIndexService.cs => AirApps/AirAppMarketIndexService.cs} (97%) rename desktop/LanMountainDesktop/{plugins/PluginMarketInstallService.cs => AirApps/AirAppMarketInstallService.cs} (79%) rename desktop/LanMountainDesktop/{plugins/PluginMarketModels.cs => AirApps/AirAppMarketModels.cs} (91%) rename desktop/LanMountainDesktop/{plugins/PluginMarketReadmeService.cs => AirApps/AirAppMarketReadmeService.cs} (91%) rename desktop/LanMountainDesktop/{plugins/PluginMarketReleaseResolverService.cs => AirApps/AirAppMarketReleaseResolverService.cs} (85%) rename desktop/LanMountainDesktop/{plugins/PluginRuntimeService.cs => AirApps/AirAppRuntimeService.cs} (63%) rename desktop/LanMountainDesktop/{plugins/PluginScopedSettingsService.cs => AirApps/AirAppScopedSettingsService.cs} (80%) rename desktop/LanMountainDesktop/{plugins/PluginSharedContractManager.cs => AirApps/AirAppSharedContractManager.cs} (92%) rename desktop/LanMountainDesktop/{plugins/DevPluginOptions.cs => AirApps/DevAirAppOptions.cs} (85%) rename desktop/LanMountainDesktop/{plugins/LoadedPlugin.cs => AirApps/LoadedAirApp.cs} (61%) rename desktop/LanMountainDesktop/{plugins => AirApps}/README.md (100%) rename desktop/LanMountainDesktop/Helpers/{PluginCatalogMarkdownHelper.cs => AirAppCatalogMarkdownHelper.cs} (95%) rename desktop/LanMountainDesktop/Services/{PluginAppearanceSnapshotMapper.cs => AirAppAppearanceSnapshotMapper.cs} (87%) rename desktop/LanMountainDesktop/Services/{PluginInstallTargetAccess.cs => AirAppInstallTargetAccess.cs} (92%) rename desktop/LanMountainDesktop/Services/{ElevatedPluginInstallService.cs => ElevatedAirAppInstallService.cs} (89%) rename desktop/LanMountainDesktop/Services/{PendingPluginUpgradeService.cs => PendingAirAppUpgradeService.cs} (81%) rename desktop/LanMountainDesktop/ViewModels/{PluginCatalogSettingsPageViewModels.cs => AirAppCatalogSettingsPageViewModels.cs} (78%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginCatalogDetailDrawer.axaml => AirAppCatalogDetailDrawer.axaml} (97%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginCatalogDetailDrawer.axaml.cs => AirAppCatalogDetailDrawer.axaml.cs} (60%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginCatalogSettingsPage.axaml => AirAppCatalogSettingsPage.axaml} (95%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginCatalogSettingsPage.axaml.cs => AirAppCatalogSettingsPage.axaml.cs} (79%) rename desktop/LanMountainDesktop/Views/SettingsPages/{GeneratedPluginSettingsPage.axaml => AirAppGeneratedSettingsPage.axaml} (89%) rename desktop/LanMountainDesktop/Views/SettingsPages/{GeneratedPluginSettingsPage.axaml.cs => AirAppGeneratedSettingsPage.axaml.cs} (73%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginsSettingsPage.axaml => AirAppsSettingsPage.axaml} (89%) rename desktop/LanMountainDesktop/Views/SettingsPages/{PluginsSettingsPage.axaml.cs => AirAppsSettingsPage.axaml.cs} (68%) delete mode 100644 desktop/LanMountainDesktop/plugins/PluginContributions.cs delete mode 100644 desktop/LanMountainDesktop/plugins/PluginLoadResult.cs delete mode 100644 desktop/LanMountainDesktop/plugins/PluginLoaderOptions.cs rename docs/{01-插件开发 => 01-AirApp开发}/01-快速开始/01-环境准备.md (63%) rename docs/{01-插件开发/01-快速开始/02-创建第一个插件.md => 01-AirApp开发/01-快速开始/02-创建第一个轻应用.md} (77%) rename docs/{01-插件开发/02-核心概念/01-插件生命周期.md => 01-AirApp开发/02-核心概念/01-轻应用生命周期.md} (77%) rename docs/{01-插件开发 => 01-AirApp开发}/02-核心概念/02-组件系统.md (97%) rename docs/{01-插件开发 => 01-AirApp开发}/02-核心概念/03-设置系统.md (93%) rename docs/{01-插件开发/03-API参考/01-IPlugin接口.md => 01-AirApp开发/03-API参考/01-IAirApp接口.md} (77%) rename docs/{01-插件开发/03-API参考/02-IPluginContext.md => 01-AirApp开发/03-API参考/02-IAirAppRuntimeContext.md} (81%) rename docs/{01-插件开发 => 01-AirApp开发}/README.md (66%) create mode 100644 docs/AIRAPP_SDK_V1_MIGRATION.md rename tests/LanMountainDesktop.Tests/{PluginAppearanceBoundaryTests.cs => AirAppAppearanceBoundaryTests.cs} (86%) rename tests/LanMountainDesktop.Tests/{PluginInstallerServiceTests.cs => AirAppInstallerServiceTests.cs} (78%) rename tests/LanMountainDesktop.Tests/{PluginManifestRuntimeTests.cs => AirAppManifestRuntimeTests.cs} (69%) rename tests/LanMountainDesktop.Tests/{PluginMarketCompatibilityTests.cs => AirAppMarketCompatibilityTests.cs} (65%) rename tests/LanMountainDesktop.Tests/{PluginMarketIndexDocumentTests.cs => AirAppMarketIndexDocumentTests.cs} (83%) rename tests/LanMountainDesktop.Tests/{PluginRuntimeDataPathTests.cs => AirAppRuntimeDataPathTests.cs} (72%) create mode 100644 tests/LanMountainDesktop.Tests/AirAppSdkVersionConsistencyTests.cs rename tests/LanMountainDesktop.Tests/{InProcPluginIpcTransportTests.cs => InProcAirAppIpcTransportTests.cs} (82%) rename tests/LanMountainDesktop.Tests/{PendingPluginUpgradeServiceTests.cs => PendingAirAppUpgradeServiceTests.cs} (70%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90edbee..62ac3b2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -227,9 +227,9 @@ jobs: if-no-files-found: warn retention-days: 7 - pack-plugin-packages: + pack-airapp-packages: runs-on: ubuntu-latest - name: Pack_Plugin_Packages + name: Pack_AirApp_Packages steps: - name: Checkout @@ -256,7 +256,7 @@ jobs: shell: pwsh run: .\scripts\Pack-PluginPackages.ps1 -Configuration Release -OutputPath .\artifacts\nuget - - name: Upload plugin package artifacts + - name: Upload AirApp package artifacts uses: actions/upload-artifact@v7 with: name: plugin-packages diff --git a/AGENTS.md b/AGENTS.md index fb6a6d6..f8fa3f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,10 +4,10 @@ ## 1. 项目目标与仓库边界 -- 本仓库是阑山桌面桌面宿主、宿主侧插件运行时、Plugin SDK、共享契约与基础外观/设置能力的权威来源。 -- 不要把插件市场元数据、开发者门户或官方示例插件实现当作本仓库内容维护。 +- 本仓库是阑山桌面桌面宿主、宿主侧 AirApp 运行时、AirApp SDK、共享契约与基础外观/设置能力的权威来源。 +- 不要把轻应用市场元数据、开发者门户或官方示例轻应用实现当作本仓库内容维护。 - 市场和生态材料属于兄弟仓库 `LanAirApp`。 -- 官方示例插件属于独立仓库 `LanMountainDesktop.SamplePlugin`。 +- 官方示例轻应用属于独立仓库 `LanMountainDesktop.SamplePlugin`。 边界详情看: @@ -16,14 +16,14 @@ ## 2. 关键目录地图 -- `desktop/LanMountainDesktop/`: 主宿主应用,包含 UI、服务、组件系统、主题与插件运行时接入 +- `desktop/LanMountainDesktop/`: 主宿主应用,包含 UI、服务、组件系统、主题与 AirApp 运行时接入 - `desktop/LanMountainDesktop/ComponentSystem/`: 内置组件定义、注册、扩展加载 -- `desktop/LanMountainDesktop/plugins/`: 宿主侧插件运行时、安装与 market 集成 +- `desktop/LanMountainDesktop/plugins/`: 宿主侧 AirApp 运行时、安装与 market 集成 - `desktop/LanMountainDesktop/Views/` and `ViewModels/`: UI 页面、窗口与视图模型 - `desktop/LanMountainDesktop/Services/`: 设置、遥测、启动、持久化、业务服务 -- `airapp/LanMountainDesktop.PluginSdk/`: 插件 SDK 公共接口和默认打包行为(含 PluginIsolation、Host.Abstractions、Settings.Core、Appearance) +- `airapp/LanMountainDesktop.AirAppSdk/`: AirApp SDK 公共接口和默认打包行为(含隔离层与宿主桥接契约) - `platform/LanMountainDesktop.Platform/`: 平台差异层(接口 + Windows/macOS 实现) -- `core/LanMountainDesktop.Core/`: 宿主/插件共享契约、IPC 基础设施与插件打包 +- `core/LanMountainDesktop.Core/`: 宿主/AirApp 共享契约、IPC 基础设施与打包 - `mobile/LanMountainDesktop.Mobile/`: 共享移动 UI 壳(组件面板) - `mobile/LanMountainDesktop.Mobile.Android/`: Android head(入口) - `tests/LanMountainDesktop.Tests/`: 宿主与 SDK 测试 @@ -40,7 +40,7 @@ dotnet run --project desktop/LanMountainDesktop/LanMountainDesktop.csproj dotnet test LanMountainDesktop.slnx -c Debug ``` -插件本地包生成: +AirApp 本地包生成: ```powershell ./scripts/Pack-PluginPackages.ps1 @@ -72,17 +72,17 @@ dotnet test LanMountainDesktop.slnx -c Debug - 设置页相关改动通常同时落在 `Views/`、`ViewModels/`、`Services/` 和 `.trae/specs/` - UI 启动与窗口生命周期主线在 `Program.cs` 和 `App.axaml.cs` -### 插件 +### AirApp -- SDK 公共 API 以 `airapp/LanMountainDesktop.PluginSdk/` 为准 +- SDK 公共 API 以 `airapp/LanMountainDesktop.AirAppSdk/` 为准 - 共享契约以 `core/LanMountainDesktop.Core/` 为准 - market 数据来源默认是兄弟仓库 `..\\LanAirApp` - 迁移或 breaking change 优先同步 `docs/PLUGIN_SDK_V5_MIGRATION.md` ### 设置与主题 -- 设置持久化和 scope 变化优先检查 `airapp/LanMountainDesktop.PluginSdk/`(合并自 `LanMountainDesktop.Settings.Core`) -- 外观、圆角、主题资源优先检查 `airapp/LanMountainDesktop.PluginSdk/`(合并自 `LanMountainDesktop.Appearance`)与专题规范 +- 设置持久化和 scope 变化优先检查 `airapp/LanMountainDesktop.AirAppSdk/`(合并自 `LanMountainDesktop.Settings.Core`) +- 外观、圆角、主题资源优先检查 `airapp/LanMountainDesktop.AirAppSdk/`(合并自 `LanMountainDesktop.Appearance`)与专题规范 - **圆角统一**:桌面组件(Widget)必须统一使用动态资源 `DesignCornerRadiusComponent`。严禁在组件根容器使用硬编码数值或非组件级令牌(如 `Xs`, `Md` 等),以确保全局圆角缩放设置能正确应用到所有组件。 ## 6. 权威来源 diff --git a/LanMountainDesktop.slnx b/LanMountainDesktop.slnx index e1cdc40..9294097 100644 --- a/LanMountainDesktop.slnx +++ b/LanMountainDesktop.slnx @@ -1,10 +1,11 @@ - + - + + diff --git a/README.md b/README.md index 430b9e4..14331da 100644 --- a/README.md +++ b/README.md @@ -37,10 +37,10 @@ - 多页桌面,工作学习场景分离 - 主题切换、玻璃效果、圆角风格 -### 🔌 插件生态 -- 通过 `.laapp` 插件扩展功能 -- 官方 Plugin SDK 支持自定义组件 -- 设置页、组件、集成功能一站式接入 +### 🔌 轻应用生态 +- 通过 `.laapp` 轻应用扩展功能 +- 官方 AirApp SDK 支持桌面组件与窗口轻应用 +- 设置页、组件、窗口、集成功能一站式接入 ## 为谁而设计 @@ -48,7 +48,7 @@ |---------|---------| | 🎓 学生用户 | 课程表、自习监测、计时、天气和日常信息聚合 | | 💼 办公用户 | 日历、资讯、最近文档、常用工具入口 | -| 🎨 效率爱好者 | 自由布局、主题切换、插件扩展 | +| 🎨 效率爱好者 | 自由布局、主题切换、轻应用扩展 | | 🇨🇳 中文用户 | 本地化界面、农历和节假日等本地语境支持 | ## 快速开始 @@ -84,37 +84,36 @@ dotnet run --project LanMountainDesktop.Launcher/LanMountainDesktop.Launcher.csp dotnet test LanMountainDesktop.slnx -c Debug ``` -## 插件开发 +## 轻应用开发 -阑山桌面支持通过 Plugin SDK 开发自定义插件: +阑山桌面通过统一的 AirApp SDK 支持轻应用扩展(桌面组件 + 窗口轻应用): ```bash -# 安装插件模板 -dotnet new install LanMountainDesktop.PluginTemplate +# 安装轻应用模板 +dotnet new install LanMountainDesktop.AirAppTemplate -# 创建新插件 -dotnet new lmd-plugin -n MyPlugin +# 创建新轻应用 +dotnet new lmd-airapp -n MyAirApp ``` -- **Plugin SDK**: `LanMountainDesktop.PluginSdk` (API 6.0.0) +- **AirApp SDK**: `LanMountainDesktop.AirAppSdk` (API 1.0.0) - **共享契约**: `LanMountainDesktop.Core` -- **迁移指南**: [PLUGIN_SDK_V5_MIGRATION.md](docs/PLUGIN_SDK_V5_MIGRATION.md) +- **迁移指南**: [AIRAPP_SDK_V1_MIGRATION.md](docs/AIRAPP_SDK_V1_MIGRATION.md) ## 项目结构 ``` LanMountainDesktop/ -├── core/ # 共享基础:契约、IPC、插件打包 +├── core/ # 共享基础:契约、IPC、打包 │ └── LanMountainDesktop.Core/ ├── platform/ # 平台差异层(接口 + Windows/macOS 实现) │ └── LanMountainDesktop.Platform/ -├── airappsdk/ # AirApp 第三方 SDK 与工具 -│ └── LanMountainDesktop.AirAppSdk/ (+ AirAppDevServer / AirAppTemplate) -├── airapp/ # 插件 SDK 与 AirApp 运行时 -│ ├── LanMountainDesktop.PluginSdk/ # 官方插件 SDK -│ ├── LanMountainDesktop.AirAppRuntime/ -│ ├── LanMountainDesktop.AirAppHost/ -│ └── LanMountainDesktop.PluginTemplate/ +├── airapp/ # AirApp 统一扩展系统 +│ ├── LanMountainDesktop.AirAppSdk/ # 统一 SDK(组件 + 窗口轻应用) +│ ├── LanMountainDesktop.AirAppRuntime/ # 轻应用运行时进程 +│ ├── LanMountainDesktop.AirAppHost/ # 轻应用窗口宿主进程 +│ ├── LanMountainDesktop.AirAppTemplate/ # dotnet new lmd-airapp 模板 +│ └── LanMountainDesktop.AirAppDevServer/ # 轻应用开发工具 ├── desktop/ # 桌面宿主 │ ├── LanMountainDesktop/ # 桌面宿主应用 │ └── LanMountainDesktop.Launcher/ # 启动器 (OOBE、Splash、版本管理、更新) @@ -131,15 +130,17 @@ LanMountainDesktop/ | 项目 | 职责 | |-----|------| -| **本仓库** | 桌面宿主、插件运行时、Plugin SDK、共享契约 | -| [LanAirApp](https://github.com/yourorg/LanAirApp) | 插件市场元数据、开发者生态材料 | -| [LanMountainDesktop.SamplePlugin](https://github.com/yourorg/LanMountainDesktop.SamplePlugin) | 官方示例插件 | +| **本仓库** | 桌面宿主、AirApp 运行时、AirApp SDK、共享契约 | +| [LanAirApp](https://github.com/yourorg/LanAirApp) | 轻应用市场元数据、开发者生态材料 | +| [LanMountainDesktop.SamplePlugin](https://github.com/yourorg/LanMountainDesktop.SamplePlugin) | 官方示例轻应用 | ## 文档索引 - [产品定位](docs/PRODUCT.md) - 产品愿景与目标用户 - [架构说明](docs/ARCHITECTURE.md) - 仓库结构与运行时主线 - [开发指南](docs/DEVELOPMENT.md) - 构建、测试、调试 +- [AirApp 开发指南](docs/01-AirApp开发/README.md) - 轻应用组件与窗口开发 +- [AirApp 迁移指南](docs/AIRAPP_SDK_V1_MIGRATION.md) - 插件迁移到 AirApp - [视觉规范](docs/VISUAL_SPEC.md) - 主题、颜色、玻璃层级 - [圆角规范](docs/CORNER_RADIUS_SPEC.md) - 圆角层级与动态规则 - [贡献指南](docs/CONTRIBUTING.md) - PR、spec、文档协作规则 diff --git a/airappsdk/LanMountainDesktop.AirAppDevServer/AirAppDevServer.cs b/airapp/LanMountainDesktop.AirAppDevServer/AirAppDevServer.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppDevServer/AirAppDevServer.cs rename to airapp/LanMountainDesktop.AirAppDevServer/AirAppDevServer.cs diff --git a/airappsdk/LanMountainDesktop.AirAppDevServer/AirAppPackager.cs b/airapp/LanMountainDesktop.AirAppDevServer/AirAppPackager.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppDevServer/AirAppPackager.cs rename to airapp/LanMountainDesktop.AirAppDevServer/AirAppPackager.cs diff --git a/airappsdk/LanMountainDesktop.AirAppDevServer/AirAppPreviewer.cs b/airapp/LanMountainDesktop.AirAppDevServer/AirAppPreviewer.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppDevServer/AirAppPreviewer.cs rename to airapp/LanMountainDesktop.AirAppDevServer/AirAppPreviewer.cs diff --git a/airappsdk/LanMountainDesktop.AirAppDevServer/LanMountainDesktop.AirAppDevServer.csproj b/airapp/LanMountainDesktop.AirAppDevServer/LanMountainDesktop.AirAppDevServer.csproj similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppDevServer/LanMountainDesktop.AirAppDevServer.csproj rename to airapp/LanMountainDesktop.AirAppDevServer/LanMountainDesktop.AirAppDevServer.csproj diff --git a/airappsdk/LanMountainDesktop.AirAppDevServer/Program.cs b/airapp/LanMountainDesktop.AirAppDevServer/Program.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppDevServer/Program.cs rename to airapp/LanMountainDesktop.AirAppDevServer/Program.cs diff --git a/airapp/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs b/airapp/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs index d88f0d0..a3a3f4f 100644 --- a/airapp/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs +++ b/airapp/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs @@ -8,7 +8,8 @@ public sealed record AirAppLaunchOptions( string? LauncherPipeName, string? InstanceKey, string? DataRoot, - string? TargetEntryId) + string? TargetEntryId, + string? AppPackagePath) { public const string WorldClockAppId = "world-clock"; public const string WhiteboardAppId = "whiteboard"; @@ -63,7 +64,8 @@ public sealed record AirAppLaunchOptions( GetOptionalValue(values, "launcher-pipe"), GetOptionalValue(values, "instance-key"), GetOptionalValue(values, "data-root"), - GetOptionalValue(values, "target-entry-id")); + GetOptionalValue(values, "target-entry-id"), + GetOptionalValue(values, "app-package")); } private static string GetValue(IReadOnlyDictionary values, string key, string fallback) diff --git a/airapp/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs b/airapp/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs index 1bc6744..04b88cc 100644 --- a/airapp/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs +++ b/airapp/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs @@ -17,6 +17,8 @@ public sealed partial class AirAppWindow : FAAppWindow private readonly AirAppWindowDescriptor _descriptor; private WhiteboardWidget? _whiteboardWidget; private string _instanceKey = string.Empty; + private AirAppWindowLoader.LoadedAirAppWindow? _loadedAirAppWindow; + private LanMountainDesktop.AirAppSdk.IAirAppWindow? _thirdPartyWindow; public AirAppWindow() : this(AirAppLaunchOptions.Parse([])) @@ -61,6 +63,12 @@ public sealed partial class AirAppWindow : FAAppWindow private void ConfigureWindow() { + if (!string.IsNullOrWhiteSpace(_options.AppPackagePath)) + { + ConfigureThirdPartyWindow(); + return; + } + ApplyWindowDescriptor(_descriptor); if (string.Equals(_options.AppId, AirAppLaunchOptions.WorldClockAppId, StringComparison.OrdinalIgnoreCase)) @@ -88,6 +96,90 @@ public sealed partial class AirAppWindow : FAAppWindow }; } + private void ConfigureThirdPartyWindow() + { + var loaded = new AirAppWindowLoader().Load(_options); + _loadedAirAppWindow = loaded; + _thirdPartyWindow = loaded.Window; + var window = loaded.Window; + + ApplySdkWindowDescriptor(window.Descriptor); + + var content = window.Content; + if (content is null) + { + throw new InvalidOperationException( + $"AirApp window '{_options.AppId}' exposes no Content. Set Content on the IAirAppWindow implementation."); + } + + ContentHost.Content = content; + _ = window.OnWindowOpeningAsync(); + AppLogger.Info( + "AirAppWindow", + $"Third-party AirApp window configured. AppId='{_options.AppId}'; TargetEntryId='{_options.TargetEntryId ?? string.Empty}'."); + } + + private void ApplySdkWindowDescriptor(LanMountainDesktop.AirAppSdk.AirAppWindowDescriptor descriptor) + { + Title = string.IsNullOrWhiteSpace(descriptor.Title) ? _options.AppId : descriptor.Title; + Width = descriptor.Width; + Height = descriptor.Height; + MinWidth = descriptor.MinWidth; + MinHeight = descriptor.MinHeight; + ShowInTaskbar = descriptor.ShowInTaskbar; + CanResize = descriptor.CanResize; + ShowAsDialog = descriptor.ShowAsDialog; + WindowState = WindowState.Normal; + WindowRoot.Background = this.TryFindResource("AirAppWindowBackgroundBrush", out var brush) && brush is IBrush backgroundBrush + ? backgroundBrush + : Brushes.White; + + switch (descriptor.ChromeMode) + { + case LanMountainDesktop.AirAppSdk.AirAppWindowChromeMode.Standard: + WindowDecorations = WindowDecorations.Full; + TitleBar.ExtendsContentIntoTitleBar = false; + TitleBar.Height = 40; + break; + + case LanMountainDesktop.AirAppSdk.AirAppWindowChromeMode.Borderless: + WindowDecorations = WindowDecorations.None; + TitleBar.ExtendsContentIntoTitleBar = true; + TitleBar.Height = 40; + break; + + case LanMountainDesktop.AirAppSdk.AirAppWindowChromeMode.FullScreen: + WindowDecorations = WindowDecorations.None; + TitleBar.ExtendsContentIntoTitleBar = true; + ShowAsDialog = false; + WindowState = WindowState.FullScreen; + TitleBar.Height = 40; + break; + + case LanMountainDesktop.AirAppSdk.AirAppWindowChromeMode.Tool: + WindowDecorations = WindowDecorations.Full; + TitleBar.ExtendsContentIntoTitleBar = false; + ShowInTaskbar = false; + CanResize = false; + TitleBar.Height = 36; + break; + + case LanMountainDesktop.AirAppSdk.AirAppWindowChromeMode.BackgroundOnly: + // Reserved for future background-only Air APPs. + break; + } + + TitleBar.BackgroundColor = Colors.Transparent; + TitleBar.ForegroundColor = Color.FromRgb(32, 32, 32); + TitleBar.InactiveBackgroundColor = Colors.Transparent; + TitleBar.InactiveForegroundColor = Color.FromRgb(96, 96, 96); + TitleBar.ButtonBackgroundColor = Colors.Transparent; + TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(23, 0, 0, 0); + TitleBar.ButtonPressedBackgroundColor = Color.FromArgb(52, 0, 0, 0); + TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + TitleBar.ButtonInactiveForegroundColor = Colors.Gray; + } + private void ApplyWindowDescriptor(AirAppWindowDescriptor descriptor) { Title = descriptor.Title; @@ -180,6 +272,7 @@ public sealed partial class AirAppWindow : FAAppWindow { base.OnOpened(e); _ = RegisterWithLauncherAsync(); + _thirdPartyWindow?.OnWindowOpened(); AppLogger.Info( "AirAppWindow", $"Opened. WindowRole=AirApp; AppId='{_options.AppId}'; ForegroundActivationRequested=True."); @@ -192,16 +285,47 @@ public sealed partial class AirAppWindow : FAAppWindow protected override void OnClosing(WindowClosingEventArgs e) { SaveWhiteboard(); + _thirdPartyWindow?.OnWindowClosing(e); base.OnClosing(e); } protected override void OnClosed(EventArgs e) { SaveAndDisposeWhiteboard(); + DisposeLoadedAirAppWindow(); _ = UnregisterWithLauncherAsync(); base.OnClosed(e); } + private void DisposeLoadedAirAppWindow() + { + var loaded = _loadedAirAppWindow; + if (loaded is null) + { + return; + } + + _loadedAirAppWindow = null; + _thirdPartyWindow = null; + try + { + loaded.Window.OnWindowClosed(); + } + catch (Exception ex) + { + AppLogger.Warn("AirAppWindow", "Failed to notify AirApp window closed.", ex); + } + + try + { + loaded.LoadedAirApp.Dispose(); + } + catch (Exception ex) + { + AppLogger.Warn("AirAppWindow", "Failed to dispose loaded AirApp window.", ex); + } + } + private void SaveAndDisposeWhiteboard() { var widget = _whiteboardWidget; diff --git a/airapp/LanMountainDesktop.AirAppHost/AirAppWindowLoader.cs b/airapp/LanMountainDesktop.AirAppHost/AirAppWindowLoader.cs new file mode 100644 index 0000000..0e1735f --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppHost/AirAppWindowLoader.cs @@ -0,0 +1,130 @@ +using System; +using System.IO; +using System.Linq; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirApps; +using LanMountainDesktop.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace LanMountainDesktop.AirAppHost; + +/// +/// Loads a third-party AirApp window into the AirAppHost process. +/// Reads the AirApp package manifest, loads the entrance assembly with the desktop +/// , resolves the requested window by id, and produces the +/// window "blueprint" (content + descriptor) to be hosted inside the FAAppWindow shell. +/// +internal sealed class AirAppWindowLoader +{ + /// + /// Result of loading a third-party AirApp window. + /// + internal sealed record LoadedAirAppWindow( + IAirAppWindow Window, + LoadedAirApp LoadedAirApp); + + public LoadedAirAppWindow Load(AirAppLaunchOptions options) + { + ArgumentNullException.ThrowIfNull(options); + + if (string.IsNullOrWhiteSpace(options.AppPackagePath)) + { + throw new InvalidOperationException("AirAppWindowLoader requires an --app-package path."); + } + + var packageDirectory = Path.GetFullPath(options.AppPackagePath); + if (!Directory.Exists(packageDirectory)) + { + throw new InvalidOperationException($"AirApp package directory was not found: '{packageDirectory}'."); + } + + var manifestPath = Path.Combine(packageDirectory, AirAppSdkInfo.ManifestFileName); + if (!File.Exists(manifestPath)) + { + throw new InvalidOperationException( + $"AirApp package directory does not contain '{AirAppSdkInfo.ManifestFileName}': '{packageDirectory}'."); + } + + var manifest = AirAppManifest.Load(manifestPath); + var assemblyPath = manifest.ResolveEntranceAssemblyPath(manifestPath); + if (!File.Exists(assemblyPath)) + { + throw new InvalidOperationException($"AirApp entrance assembly was not found: '{assemblyPath}'."); + } + + var loader = new AirAppLoader(); + var loadResult = loader.LoadFromAssembly(assemblyPath, manifest); + if (!loadResult.IsSuccess || loadResult.LoadedAirApp is null) + { + throw new InvalidOperationException( + $"Failed to load AirApp '{manifest.Id}': {loadResult.Error?.Message ?? "unknown error"}", + loadResult.Error); + } + + var loadedAirApp = loadResult.LoadedAirApp; + try + { + var windowId = ResolveWindowId(options, manifest, loadedAirApp); + var windowRegistration = loadedAirApp.Services + .GetServices() + .FirstOrDefault(registration => string.Equals(registration.WindowId, windowId, StringComparison.OrdinalIgnoreCase)); + + if (windowRegistration is null) + { + throw new InvalidOperationException( + $"AirApp '{manifest.Id}' does not declare a window with id '{windowId}'. " + + "Register windows with AddAirAppWindow in Initialize()."); + } + + var window = CreateWindow(loadedAirApp, windowRegistration); + AppLogger.Info( + "AirAppWindow", + $"Loaded third-party AirApp window. AirAppId='{manifest.Id}'; WindowId='{windowId}'; WindowType='{windowRegistration.WindowType.FullName}'."); + return new LoadedAirAppWindow(window, loadedAirApp); + } + catch + { + loadedAirApp.Dispose(); + throw; + } + } + + private static string ResolveWindowId( + AirAppLaunchOptions options, + AirAppManifest manifest, + LoadedAirApp loadedAirApp) + { + if (!string.IsNullOrWhiteSpace(options.TargetEntryId)) + { + return options.TargetEntryId.Trim(); + } + + var declaredWindows = loadedAirApp.Services.GetServices().ToArray(); + if (declaredWindows.Length == 1) + { + return declaredWindows[0].WindowId; + } + + if (manifest.Windows is { Count: > 0 }) + { + return manifest.Windows[0].Id; + } + + throw new InvalidOperationException( + $"AirApp '{manifest.Id}' exposes no windows and no --target-entry-id was provided."); + } + + private static IAirAppWindow CreateWindow(LoadedAirApp loadedAirApp, AirAppWindowRegistration registration) + { + var instance = loadedAirApp.Services.GetService(registration.WindowType); + instance ??= ActivatorUtilities.CreateInstance(loadedAirApp.Services, registration.WindowType); + + if (instance is not IAirAppWindow window) + { + throw new InvalidOperationException( + $"Window type '{registration.WindowType.FullName}' does not implement IAirAppWindow."); + } + + return window; + } +} diff --git a/airapp/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs b/airapp/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs index 625ba37..2544285 100644 --- a/airapp/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs +++ b/airapp/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs @@ -43,7 +43,8 @@ internal sealed class AirAppLifecycleService : IAirAppLifecycleService instanceKey, request.SourceComponentId, request.SourcePlacementId, - request.TargetEntryId); + request.TargetEntryId, + request.AppPackagePath); if (process is null) { return Task.FromResult(BuildResult(false, "start_failed", "AirAppHost process was not created.", null)); diff --git a/airapp/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs b/airapp/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs index bf21af0..4cf97b3 100644 --- a/airapp/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs +++ b/airapp/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs @@ -5,7 +5,7 @@ namespace LanMountainDesktop.AirAppRuntime; internal interface IAirAppProcessStarter { - Process? Start(string appId, string sessionId, string instanceKey, string? sourceComponentId, string? sourcePlacementId, string? targetEntryId = null); + Process? Start(string appId, string sessionId, string instanceKey, string? sourceComponentId, string? sourcePlacementId, string? targetEntryId = null, string? appPackagePath = null); } internal sealed class AirAppProcessStarter : IAirAppProcessStarter @@ -33,7 +33,8 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter string instanceKey, string? sourceComponentId, string? sourcePlacementId, - string? targetEntryId = null) + string? targetEntryId = null, + string? appPackagePath = null) { var hostPath = _locator.Resolve(_packageRootProvider(), _hostPathProvider()); var startInfo = CreateStartInfo(hostPath); @@ -63,6 +64,11 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter AddArgument(startInfo, "--target-entry-id", targetEntryId.Trim()); } + if (!string.IsNullOrWhiteSpace(appPackagePath)) + { + AddArgument(startInfo, "--app-package", Path.GetFullPath(appPackagePath)); + } + AirAppRuntimeLogger.Info( $"Starting AirAppHost. AppId='{appId}'; InstanceKey='{instanceKey}'; HostPath='{hostPath}'; DataRoot='{dataRoot ?? string.Empty}'."); var process = Process.Start(startInfo); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceContext.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceContext.cs similarity index 86% rename from airapp/LanMountainDesktop.PluginSdk/PluginAppearanceContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceContext.cs index d6064a9..8170dbb 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceContext.cs @@ -1,17 +1,17 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; /// /// 插件外观上下文实现,提供主题、圆角等外观资源的访问和变更通知。 /// -public sealed class PluginAppearanceContext : IPluginAppearanceContext +public sealed class AirAppAppearanceContext : IAirAppAppearanceContext { - private PluginAppearanceSnapshot _snapshot; + private AirAppAppearanceSnapshot _snapshot; /// /// 创建插件外观上下文实例。 /// /// 初始外观快照 - public PluginAppearanceContext(PluginAppearanceSnapshot snapshot) + public AirAppAppearanceContext(AirAppAppearanceSnapshot snapshot) { ArgumentNullException.ThrowIfNull(snapshot); ArgumentNullException.ThrowIfNull(snapshot.CornerRadiusTokens); @@ -25,7 +25,7 @@ public sealed class PluginAppearanceContext : IPluginAppearanceContext } /// - public PluginAppearanceSnapshot Snapshot => _snapshot; + public AirAppAppearanceSnapshot Snapshot => _snapshot; /// public event EventHandler? Changed; @@ -36,7 +36,7 @@ public sealed class PluginAppearanceContext : IPluginAppearanceContext /// /// 新的外观快照 /// 变更的属性集合 - public void UpdateSnapshot(PluginAppearanceSnapshot newSnapshot, IReadOnlyCollection changedProperties) + public void UpdateSnapshot(AirAppAppearanceSnapshot newSnapshot, IReadOnlyCollection changedProperties) { ArgumentNullException.ThrowIfNull(newSnapshot); ArgumentNullException.ThrowIfNull(changedProperties); @@ -69,7 +69,7 @@ public sealed class PluginAppearanceContext : IPluginAppearanceContext } /// - public double ResolveCornerRadius(PluginCornerRadiusPreset preset, double? minimum = null, double? maximum = null) + public double ResolveCornerRadius(AirAppCornerRadiusPreset preset, double? minimum = null, double? maximum = null) { var resolved = Math.Max(0d, _snapshot.CornerRadiusTokens.Get(preset)); if (!minimum.HasValue && !maximum.HasValue) diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceExtensions.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceExtensions.cs similarity index 74% rename from airapp/LanMountainDesktop.PluginSdk/PluginAppearanceExtensions.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceExtensions.cs index 879c5d9..2f880c4 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceExtensions.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceExtensions.cs @@ -1,12 +1,12 @@ using Avalonia; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class PluginAppearanceExtensions +public static class AirAppAppearanceExtensions { public static CornerRadius ResolveCornerRadius( - this PluginAppearanceSnapshot snapshot, - PluginCornerRadiusPreset preset) + this AirAppAppearanceSnapshot snapshot, + AirAppCornerRadiusPreset preset) { ArgumentNullException.ThrowIfNull(snapshot); var value = snapshot.CornerRadiusTokens.Get(preset); @@ -14,8 +14,8 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveCornerRadius( - this PluginAppearanceSnapshot snapshot, - PluginCornerRadiusPreset preset, + this AirAppAppearanceSnapshot snapshot, + AirAppCornerRadiusPreset preset, CornerRadius fallback) { ArgumentNullException.ThrowIfNull(snapshot); @@ -28,8 +28,8 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveCornerRadius( - this IPluginAppearanceContext context, - PluginCornerRadiusPreset preset) + this IAirAppAppearanceContext context, + AirAppCornerRadiusPreset preset) { ArgumentNullException.ThrowIfNull(context); var value = context.ResolveCornerRadius(preset); @@ -37,8 +37,8 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveCornerRadius( - this IPluginAppearanceContext context, - PluginCornerRadiusPreset preset, + this IAirAppAppearanceContext context, + AirAppCornerRadiusPreset preset, double minimum, double maximum) { @@ -48,7 +48,7 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveScaledCornerRadius( - this IPluginAppearanceContext context, + this IAirAppAppearanceContext context, double baseRadius) { ArgumentNullException.ThrowIfNull(context); @@ -57,7 +57,7 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveScaledCornerRadius( - this IPluginAppearanceContext context, + this IAirAppAppearanceContext context, double baseRadius, double minimum, double maximum) @@ -68,8 +68,8 @@ public static class PluginAppearanceExtensions } public static CornerRadius ResolveCornerRadius( - this PluginDesktopComponentContext context, - PluginCornerRadiusPreset preset, + this AirAppComponentContext context, + AirAppCornerRadiusPreset preset, double minimum, double maximum) { @@ -78,8 +78,8 @@ public static class PluginAppearanceExtensions return new CornerRadius(Math.Max(0d, value)); } - public static PluginAppearanceSnapshot GetAppearanceSnapshot( - this PluginDesktopComponentContext context) + public static AirAppAppearanceSnapshot GetAppearanceSnapshot( + this AirAppComponentContext context) { ArgumentNullException.ThrowIfNull(context); return context.Appearance.Snapshot; diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceHelper.cs similarity index 78% rename from airapp/LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceHelper.cs index dcaf3c8..1bdadea 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceHelper.cs @@ -1,11 +1,11 @@ using Avalonia; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; /// /// 插件外观辅助方法,提供统一的圆角和主题资源访问。 /// -public static class PluginAppearanceHelper +public static class AirAppAppearanceHelper { /// /// 获取桌面组件主外壳圆角半径。 @@ -13,10 +13,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 主外壳圆角半径(像素) - public static double GetShellCornerRadius(this IPluginAppearanceContext context) + public static double GetShellCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Component); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Component); } /// @@ -25,10 +25,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 内部卡片圆角半径(像素) - public static double GetCardCornerRadius(this IPluginAppearanceContext context) + public static double GetCardCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Sm); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Sm); } /// @@ -37,10 +37,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 控件圆角半径(像素) - public static double GetControlCornerRadius(this IPluginAppearanceContext context) + public static double GetControlCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Xs); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Xs); } /// @@ -49,10 +49,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 徽章圆角半径(像素) - public static double GetBadgeCornerRadius(this IPluginAppearanceContext context) + public static double GetBadgeCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Micro); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Micro); } /// @@ -61,10 +61,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 中等面板圆角半径(像素) - public static double GetMediumPanelCornerRadius(this IPluginAppearanceContext context) + public static double GetMediumPanelCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Md); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Md); } /// @@ -73,10 +73,10 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 大面板圆角半径(像素) - public static double GetLargePanelCornerRadius(this IPluginAppearanceContext context) + public static double GetLargePanelCornerRadius(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); - return context.ResolveCornerRadius(PluginCornerRadiusPreset.Lg); + return context.ResolveCornerRadius(AirAppCornerRadiusPreset.Lg); } /// @@ -85,7 +85,7 @@ public static class PluginAppearanceHelper /// 外观上下文 /// 圆角预设 /// Avalonia CornerRadius 结构 - public static CornerRadius ToCornerRadius(this IPluginAppearanceContext context, PluginCornerRadiusPreset preset) + public static CornerRadius ToCornerRadius(this IAirAppAppearanceContext context, AirAppCornerRadiusPreset preset) { ArgumentNullException.ThrowIfNull(context); var radius = context.ResolveCornerRadius(preset); @@ -97,7 +97,7 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 是否为暗色主题 - public static bool IsDarkTheme(this IPluginAppearanceContext context) + public static bool IsDarkTheme(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); return string.Equals(context.Snapshot.ThemeVariant, "Dark", StringComparison.OrdinalIgnoreCase); @@ -108,7 +108,7 @@ public static class PluginAppearanceHelper /// /// 外观上下文 /// 主题变体字符串("Light" 或 "Dark") - public static string GetThemeVariant(this IPluginAppearanceContext context) + public static string GetThemeVariant(this IAirAppAppearanceContext context) { ArgumentNullException.ThrowIfNull(context); return context.Snapshot.ThemeVariant; diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceSnapshot.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs similarity index 67% rename from airapp/LanMountainDesktop.PluginSdk/PluginAppearanceSnapshot.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs index 34ef99e..0cc1052 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginAppearanceSnapshot.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs @@ -1,11 +1,11 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; /// /// This is the runtime snapshot shape consumed by plugins inside the host process. /// It is intentionally distinct from the wire DTO with the same name in -/// LanMountainDesktop.PluginIsolation.Contracts.PluginAppearanceSnapshot. +/// LanMountainDesktop.AirAppIsolation.Contracts.AirAppAppearanceSnapshot. /// -public sealed record PluginMaterialSurfaceSnapshot( +public sealed record AirAppMaterialSurfaceSnapshot( string BackgroundColor, string BorderColor, double BlurRadius, @@ -13,16 +13,16 @@ public sealed record PluginMaterialSurfaceSnapshot( /// /// Runtime-facing appearance snapshot for plugins. This is not the same contract as the -/// wire-format snapshot in LanMountainDesktop.PluginIsolation.Contracts, even though the +/// wire-format snapshot in LanMountainDesktop.AirAppIsolation.Contracts, even though the /// type name matches. /// -public sealed record PluginAppearanceSnapshot( - PluginCornerRadiusTokens CornerRadiusTokens, +public sealed record AirAppAppearanceSnapshot( + AirAppCornerRadiusTokens CornerRadiusTokens, string ThemeVariant, string? AccentColor = null, string? SeedColor = null, string? ColorSource = null, string? SystemMaterialMode = null, IReadOnlyDictionary? ColorRoles = null, - IReadOnlyDictionary? MaterialSurfaces = null, + IReadOnlyDictionary? MaterialSurfaces = null, IReadOnlyList? WallpaperSeedCandidates = null); diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppBase.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppBase.cs similarity index 94% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppBase.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppBase.cs index 482db30..2633206 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppBase.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppBase.cs @@ -5,13 +5,13 @@ namespace LanMountainDesktop.AirAppSdk; /// /// Base class for AirApp implementations. -/// Inherit from this class and apply the [AirAppEntrance] attribute. +/// Inherit from this class and apply the attribute. /// public abstract class AirAppBase : IAirApp { /// /// Gets the runtime context after the AirApp has started. - /// Available after OnStartedAsync is called. + /// Available after is called. /// protected IAirAppRuntimeContext? RuntimeContext { get; private set; } @@ -69,9 +69,8 @@ public abstract class AirAppBase : IAirApp var options = new AirAppComponentOptions { - Id = id, - Name = name, - WidgetType = typeof(TWidget) + ComponentId = id, + DisplayName = name }; configure?.Invoke(options); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginCapabilityDeclaration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppCapabilityDeclaration.cs similarity index 76% rename from airapp/LanMountainDesktop.PluginSdk/PluginCapabilityDeclaration.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppCapabilityDeclaration.cs index 3d12ec3..ae58746 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginCapabilityDeclaration.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppCapabilityDeclaration.cs @@ -1,11 +1,11 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public sealed record PluginCapabilityDeclaration( +public sealed record AirAppCapabilityDeclaration( string Name, string Version, string? Description = null); -public static class PluginCapabilityNames +public static class AirAppCapabilityNames { public const string Settings = "settings"; public const string Appearance = "appearance"; diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentChromeContext.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentChromeContext.cs new file mode 100644 index 0000000..fb565f4 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentChromeContext.cs @@ -0,0 +1,11 @@ +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.Shared.Contracts; + +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppComponentChromeContext( + string ComponentId, + string? PlacementId, + double CellSize, + AppearanceCornerRadiusTokens CornerRadiusTokens, + AirAppSettingsScope Scope = AirAppSettingsScope.App); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentContext.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentContext.cs similarity index 57% rename from airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppComponentContext.cs index ee6bbd4..4a1f8e2 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentContext.cs @@ -1,9 +1,9 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginDesktopComponentContext +public sealed class AirAppComponentContext { - public PluginDesktopComponentContext( - PluginManifest manifest, + public AirAppComponentContext( + AirAppManifest manifest, string pluginDirectory, string dataDirectory, IServiceProvider services, @@ -11,8 +11,8 @@ public sealed class PluginDesktopComponentContext string componentId, string? placementId, double cellSize, - IPluginAppearanceContext appearance, - IPluginSettingsService? pluginSettings = null) + IAirAppAppearanceContext appearance, + IAirAppSettingsService? pluginSettings = null) { ArgumentNullException.ThrowIfNull(manifest); ArgumentException.ThrowIfNullOrWhiteSpace(pluginDirectory); @@ -23,7 +23,7 @@ public sealed class PluginDesktopComponentContext ArgumentNullException.ThrowIfNull(appearance); Manifest = manifest; - PluginDirectory = pluginDirectory; + AirAppDirectory = pluginDirectory; DataDirectory = dataDirectory; Services = services; Properties = properties; @@ -31,12 +31,12 @@ public sealed class PluginDesktopComponentContext PlacementId = string.IsNullOrWhiteSpace(placementId) ? null : placementId.Trim(); CellSize = Math.Max(1, cellSize); Appearance = appearance; - PluginSettings = pluginSettings; + AirAppSettings = pluginSettings; } - public PluginManifest Manifest { get; } + public AirAppManifest Manifest { get; } - public string PluginDirectory { get; } + public string AirAppDirectory { get; } public string DataDirectory { get; } @@ -50,22 +50,45 @@ public sealed class PluginDesktopComponentContext public double CellSize { get; } - public IPluginAppearanceContext Appearance { get; } + public IAirAppAppearanceContext Appearance { get; } - public PluginCornerRadiusTokens CornerRadiusTokens => Appearance.Snapshot.CornerRadiusTokens; + public AirAppCornerRadiusTokens CornerRadiusTokens => Appearance.Snapshot.CornerRadiusTokens; - public IPluginSettingsService? PluginSettings { get; } + public IAirAppSettingsService? AirAppSettings { get; } + + /// + /// 由宿主注入的窗口打开处理器。组件通过 打开本 AirApp 的窗口轻应用。 + /// + public Func? OpenWindowHandler { get; set; } public double ResolveScaledCornerRadius(double baseRadius, double? minimum = null, double? maximum = null) { return Appearance.ResolveScaledCornerRadius(baseRadius, minimum, maximum); } - public double ResolveCornerRadius(PluginCornerRadiusPreset preset, double? minimum = null, double? maximum = null) + public double ResolveCornerRadius(AirAppCornerRadiusPreset preset, double? minimum = null, double? maximum = null) { return Appearance.ResolveCornerRadius(preset, minimum, maximum); } + /// + /// 打开本 AirApp 声明的一个窗口轻应用。 + /// + /// 窗口标识(与 AddAirAppWindow 注册的 id 一致)。 + public Task OpenWindowAsync(string windowId) + { + ArgumentException.ThrowIfNullOrWhiteSpace(windowId); + + var handler = OpenWindowHandler; + if (handler is null) + { + throw new NotSupportedException( + $"AirApp '{Manifest.Id}' component '{ComponentId}' requested to open window '{windowId}', but the host does not support window opening for this component."); + } + + return handler(windowId); + } + public T? GetService() { return (T?)Services.GetService(typeof(T)); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorContext.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorContext.cs similarity index 79% rename from airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorContext.cs index 5851d41..d6d4387 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorContext.cs @@ -1,16 +1,16 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginDesktopComponentEditorContext +public sealed class AirAppComponentEditorContext { - public PluginDesktopComponentEditorContext( - PluginManifest manifest, + public AirAppComponentEditorContext( + AirAppManifest manifest, string pluginDirectory, string dataDirectory, IServiceProvider services, IReadOnlyDictionary properties, string componentId, string? placementId, - IPluginSettingsService? pluginSettings, + IAirAppSettingsService? pluginSettings, IComponentEditorHostContext hostContext) { ArgumentNullException.ThrowIfNull(manifest); @@ -22,19 +22,19 @@ public sealed class PluginDesktopComponentEditorContext ArgumentNullException.ThrowIfNull(hostContext); Manifest = manifest; - PluginDirectory = pluginDirectory; + AirAppDirectory = pluginDirectory; DataDirectory = dataDirectory; Services = services; Properties = properties; ComponentId = componentId.Trim(); PlacementId = string.IsNullOrWhiteSpace(placementId) ? null : placementId.Trim(); - PluginSettings = pluginSettings; + AirAppSettings = pluginSettings; HostContext = hostContext; } - public PluginManifest Manifest { get; } + public AirAppManifest Manifest { get; } - public string PluginDirectory { get; } + public string AirAppDirectory { get; } public string DataDirectory { get; } @@ -46,7 +46,7 @@ public sealed class PluginDesktopComponentEditorContext public string? PlacementId { get; } - public IPluginSettingsService? PluginSettings { get; } + public IAirAppSettingsService? AirAppSettings { get; } public IComponentEditorHostContext HostContext { get; } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorRegistration.cs similarity index 78% rename from airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorRegistration.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorRegistration.cs index 340e2b2..1db8515 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentEditorRegistration.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentEditorRegistration.cs @@ -1,12 +1,12 @@ using Avalonia.Controls; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginDesktopComponentEditorRegistration +public sealed class AirAppComponentEditorRegistration { - public PluginDesktopComponentEditorRegistration( + public AirAppComponentEditorRegistration( string componentId, - Func editorFactory, + Func editorFactory, double preferredWidth = 720d, double preferredHeight = 540d, double minScale = 0.85d, @@ -44,9 +44,9 @@ public sealed class PluginDesktopComponentEditorRegistration AspectRatio = preferredWidth / preferredHeight; } - public PluginDesktopComponentEditorRegistration( + public AirAppComponentEditorRegistration( string componentId, - Func editorFactory, + Func editorFactory, double preferredWidth = 720d, double preferredHeight = 540d, double minScale = 0.85d, @@ -63,7 +63,7 @@ public sealed class PluginDesktopComponentEditorRegistration public string ComponentId { get; } - public Func EditorFactory { get; } + public Func EditorFactory { get; } public double PreferredWidth { get; } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentOptions.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs similarity index 57% rename from airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentOptions.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs index 7820be3..3f8e210 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentOptions.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginDesktopComponentOptions +public sealed class AirAppComponentOptions { public required string ComponentId { get; init; } @@ -8,7 +8,7 @@ public sealed class PluginDesktopComponentOptions public string IconKey { get; init; } = "PuzzlePiece"; - public string Category { get; init; } = "Plugins"; + public string Category { get; init; } = "AirApps"; public int MinWidthCells { get; init; } = 2; @@ -18,7 +18,7 @@ public sealed class PluginDesktopComponentOptions public bool AllowStatusBarPlacement { get; init; } - public PluginDesktopComponentResizeMode ResizeMode { get; init; } = PluginDesktopComponentResizeMode.Proportional; + public AirAppComponentResizeMode ResizeMode { get; init; } = AirAppComponentResizeMode.Proportional; public string? DisplayNameLocalizationKey { get; init; } @@ -26,7 +26,7 @@ public sealed class PluginDesktopComponentOptions public string? DescriptionLocalizationKey { get; init; } - public PluginCornerRadiusPreset CornerRadiusPreset { get; init; } = PluginCornerRadiusPreset.Default; + public AirAppCornerRadiusPreset CornerRadiusPreset { get; init; } = AirAppCornerRadiusPreset.Default; - public Func? CornerRadiusResolver { get; init; } + public Func? CornerRadiusResolver { get; init; } } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentRegistration.cs similarity index 72% rename from airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentRegistration.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppComponentRegistration.cs index 501d165..d5a2061 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentRegistration.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentRegistration.cs @@ -1,12 +1,12 @@ using Avalonia.Controls; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginDesktopComponentRegistration +public sealed class AirAppComponentRegistration { - public PluginDesktopComponentRegistration( - Func controlFactory, - PluginDesktopComponentOptions options) + public AirAppComponentRegistration( + Func controlFactory, + AirAppComponentOptions options) { ArgumentNullException.ThrowIfNull(controlFactory); ArgumentNullException.ThrowIfNull(options); @@ -38,9 +38,9 @@ public sealed class PluginDesktopComponentRegistration CornerRadiusResolver = options.CornerRadiusResolver; } - public PluginDesktopComponentRegistration( - Func controlFactory, - PluginDesktopComponentOptions options) + public AirAppComponentRegistration( + Func controlFactory, + AirAppComponentOptions options) : this((_, context) => controlFactory(context), options) { } @@ -55,7 +55,7 @@ public sealed class PluginDesktopComponentRegistration public string? DescriptionLocalizationKey { get; } - public Func ControlFactory { get; } + public Func ControlFactory { get; } public string IconKey { get; } @@ -69,24 +69,24 @@ public sealed class PluginDesktopComponentRegistration public bool AllowStatusBarPlacement { get; } - public PluginDesktopComponentResizeMode ResizeMode { get; } + public AirAppComponentResizeMode ResizeMode { get; } - public PluginCornerRadiusPreset CornerRadiusPreset { get; } + public AirAppCornerRadiusPreset CornerRadiusPreset { get; } - public Func? CornerRadiusResolver { get; } + public Func? CornerRadiusResolver { get; } - public double ResolveCornerRadius(IPluginAppearanceContext appearance, double cellSize) + public double ResolveCornerRadius(IAirAppAppearanceContext appearance, double cellSize) { ArgumentNullException.ThrowIfNull(appearance); var resolved = CornerRadiusResolver is not null ? CornerRadiusResolver(appearance, Math.Max(1d, cellSize)) - : CornerRadiusPreset == PluginCornerRadiusPreset.Default - ? appearance.ResolveCornerRadius(PluginCornerRadiusPreset.Component) + : CornerRadiusPreset == AirAppCornerRadiusPreset.Default + ? appearance.ResolveCornerRadius(AirAppCornerRadiusPreset.Component) : appearance.ResolveCornerRadius(CornerRadiusPreset); return double.IsFinite(resolved) ? Math.Max(0d, resolved) - : appearance.ResolveCornerRadius(PluginCornerRadiusPreset.Component); + : appearance.ResolveCornerRadius(AirAppCornerRadiusPreset.Component); } } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs new file mode 100644 index 0000000..1ac955b --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs @@ -0,0 +1,7 @@ +namespace LanMountainDesktop.AirAppSdk; + +public enum AirAppComponentResizeMode +{ + Proportional = 0, + Free = 1 +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusPreset.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs similarity index 62% rename from airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusPreset.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs index 601510e..56d0fd5 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusPreset.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public enum PluginCornerRadiusPreset +public enum AirAppCornerRadiusPreset { Default = 0, Micro = 1, diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusTokens.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusTokens.cs new file mode 100644 index 0000000..e6fb65f --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusTokens.cs @@ -0,0 +1,52 @@ +using Avalonia; +using LanMountainDesktop.Shared.Contracts; + +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppCornerRadiusTokens( + double Micro, + double Xs, + double Sm, + double Md, + double Lg, + double Xl, + double Island, + double Component) +{ + public double Get(AirAppCornerRadiusPreset preset) + { + return preset switch + { + AirAppCornerRadiusPreset.Default => Component, + AirAppCornerRadiusPreset.Micro => Micro, + AirAppCornerRadiusPreset.Xs => Xs, + AirAppCornerRadiusPreset.Sm => Sm, + AirAppCornerRadiusPreset.Md => Md, + AirAppCornerRadiusPreset.Lg => Lg, + AirAppCornerRadiusPreset.Xl => Xl, + AirAppCornerRadiusPreset.Island => Island, + AirAppCornerRadiusPreset.Component => Component, + _ => Component + }; + } + + public CornerRadius ToCornerRadius(AirAppCornerRadiusPreset preset) + { + return new CornerRadius(Get(preset)); + } + + public static AirAppCornerRadiusTokens FromShared(AppearanceCornerRadiusTokens tokens) + { + ArgumentNullException.ThrowIfNull(tokens); + + return new AirAppCornerRadiusTokens( + tokens.Micro.TopLeft, + tokens.Xs.TopLeft, + tokens.Sm.TopLeft, + tokens.Md.TopLeft, + tokens.Lg.TopLeft, + tokens.Xl.TopLeft, + tokens.Island.TopLeft, + tokens.Component.TopLeft); + } +} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs similarity index 54% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs index 05fea07..38ba9ab 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppEntranceAttribute.cs @@ -1,9 +1,5 @@ namespace LanMountainDesktop.AirAppSdk; -/// -/// Marks a class as the entry point for an AirApp. -/// The marked class must inherit from AirAppBase or implement IAirApp. -/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class AirAppEntranceAttribute : Attribute { diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginHostPropertyKeys.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppHostPropertyKeys.cs similarity index 57% rename from airapp/LanMountainDesktop.PluginSdk/PluginHostPropertyKeys.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppHostPropertyKeys.cs index 83c965a..decc698 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginHostPropertyKeys.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppHostPropertyKeys.cs @@ -1,9 +1,9 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class PluginHostPropertyKeys +public static class AirAppHostPropertyKeys { public const string HostApplicationName = "HostApplicationName"; public const string HostVersion = "HostVersion"; - public const string PluginSdkApiVersion = "PluginSdkApiVersion"; + public const string AirAppSdkApiVersion = "AirAppSdkApiVersion"; public const string HostLanguageCode = "HostLanguageCode"; } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppInstalledInfo.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppInstalledInfo.cs new file mode 100644 index 0000000..90614d7 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppInstalledInfo.cs @@ -0,0 +1,8 @@ +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppInstalledInfo( + AirAppManifest Manifest, + bool IsEnabled, + bool IsLoaded, + bool IsPackage, + string? ErrorMessage); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcClient.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClient.cs similarity index 84% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcClient.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClient.cs index 1d4179e..b7cce40 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcClient.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClient.cs @@ -1,26 +1,26 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace LanMountainDesktop.PluginIsolation.Ipc; +namespace LanMountainDesktop.AirAppIsolation.Ipc; -public sealed class PluginIpcClient +public sealed class AirAppIpcClient { - public PluginIpcClient(PluginIpcClientOptions options) + public AirAppIpcClient(AirAppIpcClientOptions options) { Options = options ?? throw new ArgumentNullException(nameof(options)); SerializerContext = options.SerializerContext ?? throw new ArgumentNullException(nameof(options.SerializerContext)); SerializerOptions = SerializerContext.Options; } - public PluginIpcClientOptions Options { get; } + public AirAppIpcClientOptions Options { get; } public JsonSerializerContext SerializerContext { get; } public JsonSerializerOptions SerializerOptions { get; } - public PluginIpcRequestDispatcher? RequestDispatcher { get; set; } + public AirAppIpcRequestDispatcher? RequestDispatcher { get; set; } - public PluginIpcNotificationDispatcher? NotificationDispatcher { get; set; } + public AirAppIpcNotificationDispatcher? NotificationDispatcher { get; set; } public Task RequestAsync( string route, @@ -48,7 +48,7 @@ public sealed class PluginIpcClient if (RequestDispatcher is null) { throw new NotSupportedException( - "PluginIpcClient is not yet bound to a dotnetCampus.Ipc transport dispatcher. " + + "AirAppIpcClient is not yet bound to a dotnetCampus.Ipc transport dispatcher. " + "Wire RequestDispatcher during host/worker transport integration."); } @@ -66,7 +66,7 @@ public sealed class PluginIpcClient if (NotificationDispatcher is null) { throw new NotSupportedException( - "PluginIpcClient is not yet bound to a dotnetCampus.Ipc transport dispatcher. " + + "AirAppIpcClient is not yet bound to a dotnetCampus.Ipc transport dispatcher. " + "Wire NotificationDispatcher during host/worker transport integration."); } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClientOptions.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClientOptions.cs new file mode 100644 index 0000000..4533c5a --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcClientOptions.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; +using LanMountainDesktop.AirAppIsolation.Contracts; + +namespace LanMountainDesktop.AirAppIsolation.Ipc; + +public sealed record AirAppIpcClientOptions +{ + public required string PipeName { get; init; } + + public string ProtocolVersion { get; init; } = AirAppIsolationProtocolVersion.Current; + + public TimeSpan ConnectTimeout { get; init; } = AirAppIpcConstants.DefaultConnectTimeout; + + public TimeSpan RequestTimeout { get; init; } = AirAppIpcConstants.DefaultRequestTimeout; + + public JsonSerializerContext SerializerContext { get; init; } = AirAppIsolationJsonContext.Default; +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcConstants.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcConstants.cs similarity index 75% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcConstants.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcConstants.cs index ab4a6a1..ca7caa7 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcConstants.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcConstants.cs @@ -1,16 +1,16 @@ -using LanMountainDesktop.PluginIsolation.Contracts; +using LanMountainDesktop.AirAppIsolation.Contracts; -namespace LanMountainDesktop.PluginIsolation.Ipc; +namespace LanMountainDesktop.AirAppIsolation.Ipc; -public static class PluginIpcConstants +public static class AirAppIpcConstants { - public const string EnvironmentPluginId = "LANMOUNTAIN_PLUGIN_ID"; + public const string EnvironmentAirAppId = "LANMOUNTAIN_PLUGIN_ID"; public const string EnvironmentSessionId = "LANMOUNTAIN_PLUGIN_SESSION_ID"; public const string EnvironmentHostPipeName = "LANMOUNTAIN_PLUGIN_HOST_PIPE"; public const string EnvironmentProtocolVersion = "LANMOUNTAIN_PLUGIN_PROTOCOL_VERSION"; public const string EnvironmentRuntimeMode = "LANMOUNTAIN_PLUGIN_RUNTIME_MODE"; - public const string CommandLinePluginId = "--plugin-id"; + public const string CommandLineAirAppId = "--plugin-id"; public const string CommandLineSessionId = "--session-id"; public const string CommandLineHostPipeName = "--host-pipe-name"; public const string CommandLineProtocolVersion = "--protocol-version"; @@ -21,5 +21,5 @@ public static class PluginIpcConstants public static readonly TimeSpan DefaultHeartbeatInterval = TimeSpan.FromSeconds(5); public static readonly TimeSpan DefaultHeartbeatTimeout = TimeSpan.FromSeconds(15); - public const string DefaultProtocolVersion = PluginIsolationProtocolVersion.Current; + public const string DefaultProtocolVersion = AirAppIsolationProtocolVersion.Current; } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcDelegates.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcDelegates.cs similarity index 54% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcDelegates.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcDelegates.cs index f3fc57e..cf13c01 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcDelegates.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcDelegates.cs @@ -1,13 +1,13 @@ using System.Text.Json; -namespace LanMountainDesktop.PluginIsolation.Ipc; +namespace LanMountainDesktop.AirAppIsolation.Ipc; -public delegate Task PluginIpcRequestDispatcher( +public delegate Task AirAppIpcRequestDispatcher( string route, JsonElement? payload, CancellationToken cancellationToken); -public delegate Task PluginIpcNotificationDispatcher( +public delegate Task AirAppIpcNotificationDispatcher( string route, JsonElement? payload, CancellationToken cancellationToken); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcErrorCodes.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcErrorCodes.cs similarity index 86% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcErrorCodes.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcErrorCodes.cs index 6b1aebe..6066467 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcErrorCodes.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcErrorCodes.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public static class PluginIpcErrorCodes +public static class AirAppIpcErrorCodes { public const string ProtocolMismatch = "protocol_mismatch"; public const string SessionRejected = "session_rejected"; diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutedNotifyIds.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutedNotifyIds.cs new file mode 100644 index 0000000..768517b --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutedNotifyIds.cs @@ -0,0 +1,17 @@ +using LanMountainDesktop.AirAppIsolation.Contracts; + +namespace LanMountainDesktop.AirAppIsolation.Ipc; + +public static class AirAppIpcRoutedNotifyIds +{ + public const string SessionReady = AirAppIpcRoutes.Session.Ready; + public const string LifecycleStateChanged = AirAppIpcRoutes.Lifecycle.StateChanged; + public const string SettingsChanged = AirAppIpcRoutes.Settings.Changed; + public const string AppearanceChanged = AirAppIpcRoutes.Appearance.Changed; + public const string UiDetach = AirAppIpcRoutes.Ui.Detach; + public const string UiStateChanged = AirAppIpcRoutes.Ui.StateChanged; + public const string HeartbeatPing = AirAppIpcRoutes.Heartbeat.Ping; + public const string HeartbeatPong = AirAppIpcRoutes.Heartbeat.Pong; + public const string LogWrite = AirAppIpcRoutes.Log.Write; + public const string FaultReport = AirAppIpcRoutes.Fault.Report; +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutes.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutes.cs similarity index 94% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutes.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutes.cs index 2c9288b..79f08af 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutes.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcRoutes.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public static class PluginIpcRoutes +public static class AirAppIpcRoutes { public static class Session { diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcServer.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServer.cs similarity index 94% rename from airapp/LanMountainDesktop.PluginSdk/PluginIpcServer.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServer.cs index bfa8730..e54d84c 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcServer.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServer.cs @@ -1,9 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace LanMountainDesktop.PluginIsolation.Ipc; +namespace LanMountainDesktop.AirAppIsolation.Ipc; -public sealed class PluginIpcServer +public sealed class AirAppIpcServer { private readonly Dictionary>> _requestHandlers = new(StringComparer.OrdinalIgnoreCase); @@ -11,14 +11,14 @@ public sealed class PluginIpcServer private readonly Dictionary> _notificationHandlers = new(StringComparer.OrdinalIgnoreCase); - public PluginIpcServer(PluginIpcServerOptions options) + public AirAppIpcServer(AirAppIpcServerOptions options) { Options = options ?? throw new ArgumentNullException(nameof(options)); SerializerContext = options.SerializerContext ?? throw new ArgumentNullException(nameof(options.SerializerContext)); SerializerOptions = SerializerContext.Options; } - public PluginIpcServerOptions Options { get; } + public AirAppIpcServerOptions Options { get; } public JsonSerializerContext SerializerContext { get; } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServerOptions.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServerOptions.cs new file mode 100644 index 0000000..0a5e2cb --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIpcServerOptions.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; +using LanMountainDesktop.AirAppIsolation.Contracts; + +namespace LanMountainDesktop.AirAppIsolation.Ipc; + +public sealed record AirAppIpcServerOptions +{ + public required string PipeName { get; init; } + + public string ProtocolVersion { get; init; } = AirAppIsolationProtocolVersion.Current; + + public TimeSpan HeartbeatInterval { get; init; } = AirAppIpcConstants.DefaultHeartbeatInterval; + + public TimeSpan HeartbeatTimeout { get; init; } = AirAppIpcConstants.DefaultHeartbeatTimeout; + + public JsonSerializerContext SerializerContext { get; init; } = AirAppIsolationJsonContext.Default; +} diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationJsonContext.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationJsonContext.cs new file mode 100644 index 0000000..8f28f42 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationJsonContext.cs @@ -0,0 +1,40 @@ +using System.Text.Json.Serialization; + +namespace LanMountainDesktop.AirAppIsolation.Contracts; + +[JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(AirAppCapabilityDeclaration))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(AirAppSessionHandshakeRequest))] +[JsonSerializable(typeof(AirAppSessionHandshakeResponse))] +[JsonSerializable(typeof(AirAppReadyNotification))] +[JsonSerializable(typeof(AirAppInitializeRequest))] +[JsonSerializable(typeof(AirAppInitializeResponse))] +[JsonSerializable(typeof(AirAppStopRequest))] +[JsonSerializable(typeof(AirAppRestartRequest))] +[JsonSerializable(typeof(AirAppLifecycleStateChanged))] +[JsonSerializable(typeof(AirAppSettingsSnapshotRequest))] +[JsonSerializable(typeof(AirAppSettingsSnapshotResponse))] +[JsonSerializable(typeof(AirAppSettingsWriteRequest))] +[JsonSerializable(typeof(AirAppSettingsWriteResponse))] +[JsonSerializable(typeof(AirAppSettingsChangedNotification))] +[JsonSerializable(typeof(AirAppAppearanceSnapshotRequest))] +[JsonSerializable(typeof(AirAppMaterialSurfaceSnapshot))] +[JsonSerializable(typeof(AirAppAppearanceSnapshot))] +[JsonSerializable(typeof(AirAppAppearanceChangedNotification))] +[JsonSerializable(typeof(AirAppUiSurfaceDescriptor))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(AirAppUiAttachRequest))] +[JsonSerializable(typeof(AirAppUiAttachResponse))] +[JsonSerializable(typeof(AirAppUiDetachNotification))] +[JsonSerializable(typeof(AirAppUiCommandRequest))] +[JsonSerializable(typeof(AirAppUiCommandResponse))] +[JsonSerializable(typeof(AirAppUiStateChangedNotification))] +[JsonSerializable(typeof(AirAppHeartbeatPing))] +[JsonSerializable(typeof(AirAppHeartbeatPong))] +[JsonSerializable(typeof(AirAppLogEntry))] +[JsonSerializable(typeof(AirAppFaultReport))] +public partial class AirAppIsolationJsonContext : JsonSerializerContext; diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationProtocolVersion.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationProtocolVersion.cs new file mode 100644 index 0000000..d31c14d --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppIsolationProtocolVersion.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppIsolation.Contracts; + +public static class AirAppIsolationProtocolVersion +{ + public const string Current = "1.0"; +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginLocalizer.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppLocalizer.cs similarity index 83% rename from airapp/LanMountainDesktop.PluginSdk/PluginLocalizer.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppLocalizer.cs index 3dc58ee..6c723e7 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginLocalizer.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppLocalizer.cs @@ -1,9 +1,9 @@ using System.Globalization; using System.Text.Json; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginLocalizer +public sealed class AirAppLocalizer { private static readonly JsonSerializerOptions JsonOptions = new() { @@ -14,28 +14,28 @@ public sealed class PluginLocalizer private readonly Dictionary> _cache = new(StringComparer.OrdinalIgnoreCase); - public PluginLocalizer(string pluginDirectory, string? languageCode) + public AirAppLocalizer(string pluginDirectory, string? languageCode) { ArgumentException.ThrowIfNullOrWhiteSpace(pluginDirectory); - PluginDirectory = pluginDirectory; + AirAppDirectory = pluginDirectory; LanguageCode = NormalizeLanguageCode(languageCode); } - public string PluginDirectory { get; } + public string AirAppDirectory { get; } public string LanguageCode { get; } - public static PluginLocalizer Create(IPluginRuntimeContext context) + public static AirAppLocalizer Create(IAirAppRuntimeContext context) { ArgumentNullException.ThrowIfNull(context); - return new PluginLocalizer(context.PluginDirectory, ResolveLanguageCode(context.Properties)); + return new AirAppLocalizer(context.AirAppDirectory, ResolveLanguageCode(context.Properties)); } - public static PluginLocalizer Create(PluginDesktopComponentContext context) + public static AirAppLocalizer Create(AirAppComponentContext context) { ArgumentNullException.ThrowIfNull(context); - return new PluginLocalizer(context.PluginDirectory, ResolveLanguageCode(context.Properties)); + return new AirAppLocalizer(context.AirAppDirectory, ResolveLanguageCode(context.Properties)); } public string GetString(string key, string fallback) @@ -76,7 +76,7 @@ public sealed class PluginLocalizer { ArgumentNullException.ThrowIfNull(properties); - return properties.TryGetValue(PluginHostPropertyKeys.HostLanguageCode, out var rawValue) && + return properties.TryGetValue(AirAppHostPropertyKeys.HostLanguageCode, out var rawValue) && rawValue is string languageCode ? NormalizeLanguageCode(languageCode) : NormalizeLanguageCode(CultureInfo.CurrentUICulture.Name); @@ -92,7 +92,7 @@ public sealed class PluginLocalizer var result = new Dictionary(StringComparer.OrdinalIgnoreCase); try { - var filePath = Path.Combine(PluginDirectory, "Localization", $"{languageCode}.json"); + var filePath = Path.Combine(AirAppDirectory, "Localization", $"{languageCode}.json"); if (File.Exists(filePath)) { var json = File.ReadAllText(filePath).TrimStart('\uFEFF'); diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppManifest.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppManifest.cs similarity index 70% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppManifest.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppManifest.cs index 662fa25..b984e48 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppManifest.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppManifest.cs @@ -2,9 +2,6 @@ using System.Text.Json; namespace LanMountainDesktop.AirAppSdk; -/// -/// AirApp manifest (airapp.json). -/// public sealed record AirAppManifest( string Id, string Name, @@ -13,11 +10,11 @@ public sealed record AirAppManifest( string? Author = null, string? Version = null, string? ApiVersion = null, + IReadOnlyList? SharedContracts = null, AirAppRuntimeConfiguration? Runtime = null, IReadOnlyList? Components = null, IReadOnlyList? Windows = null, - IReadOnlyList? Permissions = null, - IReadOnlyList? SharedContracts = null) + IReadOnlyList? Permissions = null) { private static readonly JsonSerializerOptions SerializerOptions = new() { @@ -26,9 +23,6 @@ public sealed record AirAppManifest( AllowTrailingCommas = true }; - /// - /// Load manifest from file. - /// public static AirAppManifest Load(string manifestPath) { ArgumentException.ThrowIfNullOrWhiteSpace(manifestPath); @@ -37,9 +31,6 @@ public sealed record AirAppManifest( return Load(stream, manifestPath); } - /// - /// Load manifest from stream. - /// public static AirAppManifest Load(Stream stream, string sourceName) { ArgumentNullException.ThrowIfNull(stream); @@ -48,15 +39,12 @@ public sealed record AirAppManifest( var manifest = JsonSerializer.Deserialize(stream, SerializerOptions); if (manifest is null) { - throw new InvalidOperationException($"Failed to deserialize AirApp manifest '{sourceName}'."); + throw new InvalidOperationException($"Failed to deserialize plugin manifest '{sourceName}'."); } return manifest.NormalizeAndValidate(sourceName); } - /// - /// Resolve entrance assembly path. - /// public string ResolveEntranceAssemblyPath(string manifestPath) { ArgumentException.ThrowIfNullOrWhiteSpace(manifestPath); @@ -67,21 +55,18 @@ public sealed record AirAppManifest( } var manifestDirectory = Path.GetDirectoryName(Path.GetFullPath(manifestPath)) - ?? throw new InvalidOperationException($"Failed to determine directory of '{manifestPath}'."); + ?? throw new InvalidOperationException($"Failed to determine the directory of '{manifestPath}'."); return Path.GetFullPath(Path.Combine(manifestDirectory, EntranceAssembly)); } - /// - /// Get runtime mode. - /// public AirAppRuntimeMode RuntimeMode => AirAppRuntimeModes.TryParse(Runtime?.Mode, out var mode) ? mode : AirAppRuntimeMode.InProcess; private AirAppManifest NormalizeAndValidate(string manifestPath) { + var normalizedSharedContracts = NormalizeSharedContracts(manifestPath, SharedContracts); var normalizedRuntime = (Runtime ?? new AirAppRuntimeConfiguration()).NormalizeAndValidate(manifestPath); - var normalized = this with { Id = RequireValue(Id, nameof(Id), manifestPath), @@ -91,18 +76,17 @@ public sealed record AirAppManifest( Author = NormalizeOptionalValue(Author), Version = NormalizeOptionalValue(Version), ApiVersion = NormalizeOptionalValue(ApiVersion) ?? AirAppSdkInfo.ApiVersion, + SharedContracts = normalizedSharedContracts, Runtime = normalizedRuntime, Components = Components ?? Array.Empty(), Windows = Windows ?? Array.Empty(), - Permissions = Permissions ?? Array.Empty(), - SharedContracts = SharedContracts ?? Array.Empty() + Permissions = Permissions ?? Array.Empty() }; - // Validate API version if (!System.Version.TryParse(normalized.ApiVersion, out var requestedVersion)) { throw new InvalidOperationException( - $"AirApp manifest '{manifestPath}' declares invalid API version '{normalized.ApiVersion}'."); + $"AirApp manifest '{manifestPath}' declares an invalid API version '{normalized.ApiVersion}'."); } if (!System.Version.TryParse(AirAppSdkInfo.ApiVersion, out var currentVersion)) @@ -113,10 +97,43 @@ public sealed record AirAppManifest( if (requestedVersion.Major != currentVersion.Major) { throw new InvalidOperationException( - $"AirApp '{normalized.Id}' targets API version '{normalized.ApiVersion}' (major {requestedVersion.Major}), " + - $"but the host provides '{AirAppSdkInfo.ApiVersion}' (major {currentVersion.Major}). " + - $"This host only supports v{currentVersion.Major}.x AirApps and rejects v{requestedVersion.Major}.x packages. " + - $"Migrate the AirApp manifest and code to API {AirAppSdkInfo.ApiVersion}, then rebuild and republish."); + $"AirApp '{normalized.Id}' targets API version '{normalized.ApiVersion}', " + + $"but the host provides '{AirAppSdkInfo.ApiVersion}'. " + + $"This host only supports API {AirAppSdkInfo.ApiVersion} plugins."); + } + + return normalized; + } + + private static IReadOnlyList NormalizeSharedContracts( + string manifestPath, + IReadOnlyList? sharedContracts) + { + if (sharedContracts is null || sharedContracts.Count == 0) + { + return Array.Empty(); + } + + var normalized = new List(sharedContracts.Count); + var seenIds = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (var contract in sharedContracts) + { + if (contract is null) + { + throw new InvalidOperationException( + $"AirApp manifest '{manifestPath}' contains a null shared contract declaration."); + } + + var normalizedContract = contract.NormalizeAndValidate(manifestPath); + var contractKey = $"{normalizedContract.Id}@{normalizedContract.Version}"; + if (!seenIds.Add(contractKey)) + { + throw new InvalidOperationException( + $"AirApp manifest '{manifestPath}' declares duplicate shared contract '{contractKey}'."); + } + + normalized.Add(normalizedContract); } return normalized; @@ -141,7 +158,7 @@ public sealed record AirAppManifest( } /// -/// Component declaration in manifest. +/// Component declaration in the AirApp manifest. /// public sealed record AirAppComponentManifest( string Id, @@ -153,7 +170,7 @@ public sealed record AirAppComponentManifest( string? IconKey = null); /// -/// Window declaration in manifest. +/// Window declaration in the AirApp manifest. /// public sealed record AirAppWindowManifest( string Id, @@ -161,28 +178,3 @@ public sealed record AirAppWindowManifest( double DefaultWidth = 800, double DefaultHeight = 600, string? Description = null); - -/// -/// Shared contract reference. -/// -public sealed record AirAppSharedContractReference( - string Id, - string Version); - -/// -/// Runtime configuration. -/// -public sealed record AirAppRuntimeConfiguration -{ - public string? Mode { get; init; } - public IReadOnlyList? Capabilities { get; init; } - - internal AirAppRuntimeConfiguration NormalizeAndValidate(string manifestPath) - { - return this with - { - Mode = string.IsNullOrWhiteSpace(Mode) ? "in-process" : Mode.Trim().ToLowerInvariant(), - Capabilities = Capabilities ?? Array.Empty() - }; - } -} diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppPackageInstallResult.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppPackageInstallResult.cs new file mode 100644 index 0000000..7f7676a --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppPackageInstallResult.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppPackageInstallResult( + AirAppManifest Manifest, + bool ReplacedExisting, + bool RestartRequired); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceDescriptor.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceDescriptor.cs similarity index 50% rename from airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceDescriptor.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceDescriptor.cs index 3a5b983..3f94527 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceDescriptor.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceDescriptor.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed record PluginPublicIpcServiceDescriptor( +public sealed record AirAppPublicIpcServiceDescriptor( Type ContractType, object Implementation, string? ObjectId, diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceRegistration.cs new file mode 100644 index 0000000..ae595d1 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppPublicIpcServiceRegistration.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppPublicIpcServiceRegistration( + Type ContractType, + string? ObjectId, + string[] NotifyIds); diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeConfiguration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeConfiguration.cs new file mode 100644 index 0000000..6e7e2b3 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeConfiguration.cs @@ -0,0 +1,15 @@ +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppRuntimeConfiguration(string Mode = AirAppRuntimeModes.InProcess) +{ + public AirAppRuntimeMode RuntimeMode => + AirAppRuntimeModes.TryParse(Mode, out var mode) ? mode : AirAppRuntimeMode.InProcess; + + internal AirAppRuntimeConfiguration NormalizeAndValidate(string manifestPath) + { + return this with + { + Mode = AirAppRuntimeModes.NormalizeManifestValue(Mode, manifestPath) + }; + } +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeMode.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs similarity index 51% rename from airapp/LanMountainDesktop.PluginSdk/PluginRuntimeMode.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs index dd93240..ab476ed 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeMode.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public enum PluginRuntimeMode +public enum AirAppRuntimeMode { InProcess = 0, IsolatedBackground = 1, diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeModes.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeModes.cs similarity index 64% rename from airapp/LanMountainDesktop.PluginSdk/PluginRuntimeModes.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeModes.cs index 8d52ab4..2eabbfe 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeModes.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppRuntimeModes.cs @@ -1,25 +1,27 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class PluginRuntimeModes +public static class AirAppRuntimeModes { public const string InProcess = "in-proc"; + public const string InProcessAlt = "in-process"; public const string IsolatedBackground = "isolated-background"; public const string IsolatedWindow = "isolated-window"; - public static bool TryParse(string? value, out PluginRuntimeMode mode) + public static bool TryParse(string? value, out AirAppRuntimeMode mode) { switch (value?.Trim().ToLowerInvariant()) { case null: case "": case InProcess: - mode = PluginRuntimeMode.InProcess; + case InProcessAlt: + mode = AirAppRuntimeMode.InProcess; return true; case IsolatedBackground: - mode = PluginRuntimeMode.IsolatedBackground; + mode = AirAppRuntimeMode.IsolatedBackground; return true; case IsolatedWindow: - mode = PluginRuntimeMode.IsolatedWindow; + mode = AirAppRuntimeMode.IsolatedWindow; return true; default: mode = default; @@ -27,7 +29,7 @@ public static class PluginRuntimeModes } } - public static PluginRuntimeMode Parse(string? value, string sourceName, string propertyName = "runtime.mode") + public static AirAppRuntimeMode Parse(string? value, string sourceName, string propertyName = "runtime.mode") { if (TryParse(value, out var mode)) { @@ -36,7 +38,7 @@ public static class PluginRuntimeModes var candidate = string.IsNullOrWhiteSpace(value) ? "" : value.Trim(); throw new InvalidOperationException( - $"Plugin manifest '{sourceName}' declares unsupported runtime mode '{candidate}' in '{propertyName}'. " + + $"AirApp manifest '{sourceName}' declares unsupported runtime mode '{candidate}' in '{propertyName}'. " + $"Supported values: '{InProcess}', '{IsolatedBackground}', '{IsolatedWindow}'."); } @@ -45,13 +47,13 @@ public static class PluginRuntimeModes return ToManifestValue(Parse(value, sourceName, propertyName)); } - public static string ToManifestValue(PluginRuntimeMode mode) + public static string ToManifestValue(AirAppRuntimeMode mode) { return mode switch { - PluginRuntimeMode.InProcess => InProcess, - PluginRuntimeMode.IsolatedBackground => IsolatedBackground, - PluginRuntimeMode.IsolatedWindow => IsolatedWindow, + AirAppRuntimeMode.InProcess => InProcess, + AirAppRuntimeMode.IsolatedBackground => IsolatedBackground, + AirAppRuntimeMode.IsolatedWindow => IsolatedWindow, _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Unsupported plugin runtime mode.") }; } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginSdkInfo.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs similarity index 57% rename from airapp/LanMountainDesktop.PluginSdk/PluginSdkInfo.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs index 415b786..f8f946b 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginSdkInfo.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs @@ -1,9 +1,10 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class PluginSdkInfo +public static class AirAppSdkInfo { - public const string ApiVersion = "5.0.0"; - public const string ManifestFileName = "plugin.json"; + public const string SdkVersion = "1.0.0"; + public const string ApiVersion = "1.0.0"; + public const string ManifestFileName = "airapp.json"; public const string PackageFileExtension = ".laapp"; public const string DataDirectoryName = "Data"; public const string RuntimeDirectoryName = ".runtime"; diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginServiceCollectionExtensions.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs similarity index 68% rename from airapp/LanMountainDesktop.PluginSdk/PluginServiceCollectionExtensions.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs index 8ef9139..eb20f2e 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginServiceCollectionExtensions.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs @@ -2,15 +2,15 @@ using Avalonia.Controls; using dotnetCampus.Ipc.CompilerServices.Attributes; using Microsoft.Extensions.DependencyInjection; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class PluginServiceCollectionExtensions +public static class AirAppServiceCollectionExtensions { - public static IServiceCollection AddPluginSettingsSection( + public static IServiceCollection AddAirAppSettingsSection( this IServiceCollection services, string id, string titleLocalizationKey, - Action configure, + Action configure, string? descriptionLocalizationKey = null, string iconKey = "PuzzlePiece", int sortOrder = 0) @@ -18,7 +18,7 @@ public static class PluginServiceCollectionExtensions ArgumentNullException.ThrowIfNull(services); ArgumentNullException.ThrowIfNull(configure); - var builder = new PluginSettingsSectionBuilder( + var builder = new AirAppSettingsSectionBuilder( id, titleLocalizationKey, descriptionLocalizationKey, @@ -35,19 +35,19 @@ public static class PluginServiceCollectionExtensions /// in the settings window, allowing the plugin to use any Fluent Avalonia controls /// and custom layouts — just like built-in settings pages. /// - /// A subclass that defines the settings UI using AXAML. - public static IServiceCollection AddPluginSettingsSection( + /// A subclass that defines the settings UI using AXAML. + public static IServiceCollection AddAirAppSettingsSection( this IServiceCollection services, string id, string titleLocalizationKey, string? descriptionLocalizationKey = null, string iconKey = "PuzzlePiece", int sortOrder = 0) - where TView : SettingsPageBase + where TView : AirAppSettingsPageBase { ArgumentNullException.ThrowIfNull(services); - var builder = new PluginSettingsSectionBuilder( + var builder = new AirAppSettingsSectionBuilder( id, titleLocalizationKey, descriptionLocalizationKey, @@ -58,21 +58,21 @@ public static class PluginServiceCollectionExtensions return services; } - public static IServiceCollection AddPluginDesktopComponent( + public static IServiceCollection AddAirAppComponent( this IServiceCollection services, - PluginDesktopComponentOptions options) + AirAppComponentOptions options) where TControl : Control { ArgumentNullException.ThrowIfNull(services); ArgumentNullException.ThrowIfNull(options); - services.AddSingleton(new PluginDesktopComponentRegistration( + services.AddSingleton(new AirAppComponentRegistration( (provider, context) => ActivatorUtilities.CreateInstance(provider, context), options)); return services; } - public static IServiceCollection AddPluginDesktopComponentEditor( + public static IServiceCollection AddAirAppComponentEditor( this IServiceCollection services, string componentId, double preferredWidth = 720d, @@ -83,7 +83,7 @@ public static class PluginServiceCollectionExtensions { ArgumentNullException.ThrowIfNull(services); - services.AddSingleton(new PluginDesktopComponentEditorRegistration( + services.AddSingleton(new AirAppComponentEditorRegistration( componentId, (provider, context) => ActivatorUtilities.CreateInstance(provider, context), preferredWidth, @@ -93,7 +93,28 @@ public static class PluginServiceCollectionExtensions return services; } - public static IServiceCollection AddPluginExport(this IServiceCollection services) + /// + /// Registers a window AirApp entry. + /// The host resolves the window by and hosts its + /// content inside the AirAppHost window shell. + /// + /// A class implementing . + /// Unique window identifier. + /// Display name. + public static IServiceCollection AddAirAppWindow( + this IServiceCollection services, + string id, + string name) + where TWindow : class, IAirAppWindow + { + ArgumentNullException.ThrowIfNull(services); + + services.AddTransient(); + services.AddSingleton(new AirAppWindowRegistration(id, name, typeof(TWindow))); + return services; + } + + public static IServiceCollection AddAirAppExport(this IServiceCollection services) where TContract : class where TImplementation : class, TContract { @@ -102,18 +123,18 @@ public static class PluginServiceCollectionExtensions EnsureSingletonRegistration(services); if (!services.Any(descriptor => - descriptor.ServiceType == typeof(PluginServiceExportRegistration) && - descriptor.ImplementationInstance is PluginServiceExportRegistration existing && + descriptor.ServiceType == typeof(AirAppServiceExportRegistration) && + descriptor.ImplementationInstance is AirAppServiceExportRegistration existing && existing.ContractType == typeof(TContract) && existing.ImplementationType == typeof(TImplementation))) { - services.AddSingleton(new PluginServiceExportRegistration(typeof(TContract), typeof(TImplementation))); + services.AddSingleton(new AirAppServiceExportRegistration(typeof(TContract), typeof(TImplementation))); } return services; } - public static IServiceCollection AddPluginPublicIpc( + public static IServiceCollection AddAirAppPublicIpc( this IServiceCollection services, string? objectId = null, params string[] notifyIds) @@ -125,12 +146,12 @@ public static class PluginServiceCollectionExtensions EnsureSingletonRegistration(services); if (!services.Any(descriptor => - descriptor.ServiceType == typeof(PluginPublicIpcServiceRegistration) && - descriptor.ImplementationInstance is PluginPublicIpcServiceRegistration existing && + descriptor.ServiceType == typeof(AirAppPublicIpcServiceRegistration) && + descriptor.ImplementationInstance is AirAppPublicIpcServiceRegistration existing && existing.ContractType == typeof(TContract) && string.Equals(existing.ObjectId, objectId, StringComparison.Ordinal))) { - services.AddSingleton(new PluginPublicIpcServiceRegistration( + services.AddSingleton(new AirAppPublicIpcServiceRegistration( typeof(TContract), objectId, notifyIds ?? [])); @@ -139,11 +160,11 @@ public static class PluginServiceCollectionExtensions return services; } - public static IServiceCollection AddPluginPublicIpcContributor(this IServiceCollection services) - where TContributor : class, IPluginPublicIpcContributor + public static IServiceCollection AddAirAppPublicIpcContributor(this IServiceCollection services) + where TContributor : class, IAirAppPublicIpcContributor { ArgumentNullException.ThrowIfNull(services); - services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportDescriptor.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportDescriptor.cs new file mode 100644 index 0000000..b5f8e6c --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportDescriptor.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppSdk; + +public sealed record AirAppServiceExportDescriptor( + string ProviderAirAppId, + Type ContractType, + object ServiceInstance); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginServiceExportRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportRegistration.cs similarity index 67% rename from airapp/LanMountainDesktop.PluginSdk/PluginServiceExportRegistration.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportRegistration.cs index 016b5b4..d999263 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginServiceExportRegistration.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppServiceExportRegistration.cs @@ -1,8 +1,8 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginServiceExportRegistration +public sealed class AirAppServiceExportRegistration { - public PluginServiceExportRegistration(Type contractType, Type implementationType) + public AirAppServiceExportRegistration(Type contractType, Type implementationType) { ArgumentNullException.ThrowIfNull(contractType); ArgumentNullException.ThrowIfNull(implementationType); diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionChoice.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionChoice.cs similarity index 65% rename from airapp/LanMountainDesktop.PluginSdk/SettingsOptionChoice.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionChoice.cs index b4e9075..3e8a3a1 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionChoice.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionChoice.cs @@ -1,8 +1,8 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class SettingsOptionChoice +public sealed class AirAppSettingOptionChoice { - public SettingsOptionChoice(string value, string titleLocalizationKey) + public AirAppSettingOptionChoice(string value, string titleLocalizationKey) { ArgumentException.ThrowIfNullOrWhiteSpace(value); ArgumentException.ThrowIfNullOrWhiteSpace(titleLocalizationKey); diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionDefinition.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionDefinition.cs similarity index 77% rename from airapp/LanMountainDesktop.PluginSdk/SettingsOptionDefinition.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionDefinition.cs index 188956c..c556374 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionDefinition.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionDefinition.cs @@ -1,16 +1,16 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class SettingsOptionDefinition +public sealed class AirAppSettingOptionDefinition { - public SettingsOptionDefinition( + public AirAppSettingOptionDefinition( string key, - SettingsOptionType optionType, + AirAppSettingOptionType optionType, string titleLocalizationKey, string? descriptionLocalizationKey = null, object? defaultValue = null, - IReadOnlyList? choices = null, + IReadOnlyList? choices = null, double? minimum = null, double? maximum = null, string? validationPattern = null) @@ -35,7 +35,7 @@ public sealed class SettingsOptionDefinition public string Key { get; } - public SettingsOptionType OptionType { get; } + public AirAppSettingOptionType OptionType { get; } public string TitleLocalizationKey { get; } @@ -43,7 +43,7 @@ public sealed class SettingsOptionDefinition public object? DefaultValue { get; } - public IReadOnlyList Choices { get; } + public IReadOnlyList Choices { get; } public double? Minimum { get; } diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionType.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionType.cs similarity index 55% rename from airapp/LanMountainDesktop.PluginSdk/SettingsOptionType.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionType.cs index a050567..bebf0da 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsOptionType.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingOptionType.cs @@ -1,6 +1,6 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public enum SettingsOptionType +public enum AirAppSettingOptionType { Toggle = 0, Select = 1, diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsCategories.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsCategories.cs similarity index 53% rename from airapp/LanMountainDesktop.PluginSdk/SettingsCategories.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsCategories.cs index 72c64a2..291ff67 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsCategories.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsCategories.cs @@ -1,14 +1,14 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public static class SettingsCategories +public static class AirAppSettingsCategories { public const string General = "General"; public const string Appearance = "Appearance"; public const string Components = "Components"; - public const string Plugins = "Plugins"; - public const string PluginCatalog = "PluginCatalog"; - [Obsolete("Use PluginCatalog instead.")] - public const string PluginMarket = PluginCatalog; + public const string AirApps = "AirApps"; + public const string AirAppCatalog = "AirAppCatalog"; + [Obsolete("Use AirAppCatalog instead.")] + public const string AirAppMarket = AirAppCatalog; public const string Update = "Update"; public const string About = "About"; public const string Advanced = "Advanced"; diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsPageBase.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageBase.cs similarity index 92% rename from airapp/LanMountainDesktop.PluginSdk/SettingsPageBase.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageBase.cs index d70e110..f1b1b15 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsPageBase.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageBase.cs @@ -1,9 +1,9 @@ using System; using Avalonia.Controls; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public abstract class SettingsPageBase : UserControl +public abstract class AirAppSettingsPageBase : UserControl { public static readonly string DialogHostIdentifier = "LanMountainDesktop.SettingsWindow"; diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageCategory.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageCategory.cs new file mode 100644 index 0000000..4a6e42d --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageCategory.cs @@ -0,0 +1,14 @@ +namespace LanMountainDesktop.AirAppSdk; + +public enum AirAppSettingsPageCategory +{ + General = 0, + Appearance = 10, + Components = 20, + AirApps = 30, + AirAppCatalog = 35, + [Obsolete("Use AirAppCatalog instead.")] + AirAppMarket = 35, + About = 40, + Dev = 50 +} diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsPageInfoAttribute.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageInfoAttribute.cs similarity index 72% rename from airapp/LanMountainDesktop.PluginSdk/SettingsPageInfoAttribute.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageInfoAttribute.cs index 950132d..daaa136 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsPageInfoAttribute.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsPageInfoAttribute.cs @@ -1,14 +1,14 @@ using System; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -public sealed class SettingsPageInfoAttribute : Attribute +public sealed class AirAppSettingsPageInfoAttribute : Attribute { - public SettingsPageInfoAttribute( + public AirAppSettingsPageInfoAttribute( string id, string name, - SettingsPageCategory category) + AirAppSettingsPageCategory category) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentException.ThrowIfNullOrWhiteSpace(name); @@ -22,7 +22,7 @@ public sealed class SettingsPageInfoAttribute : Attribute public string Name { get; } - public SettingsPageCategory Category { get; } + public AirAppSettingsPageCategory Category { get; } public string? TitleLocalizationKey { get; init; } @@ -42,5 +42,5 @@ public sealed class SettingsPageInfoAttribute : Attribute public string? GroupId { get; init; } - public SettingsScope Scope { get; init; } = SettingsScope.App; + public AirAppSettingsScope Scope { get; init; } = AirAppSettingsScope.App; } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsScope.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsScope.cs new file mode 100644 index 0000000..72b609f --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsScope.cs @@ -0,0 +1,9 @@ +namespace LanMountainDesktop.AirAppSdk; + +public enum AirAppSettingsScope +{ + App = 0, + Launcher = 1, + AirApp = 2, + ComponentInstance = 3 +} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionBuilder.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionBuilder.cs similarity index 65% rename from airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionBuilder.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionBuilder.cs index 5450a5f..1a48f8a 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionBuilder.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionBuilder.cs @@ -2,14 +2,14 @@ using System; using System.Collections.Generic; using Avalonia.Controls; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginSettingsSectionBuilder +public sealed class AirAppSettingsSectionBuilder { - private readonly List _options = []; + private readonly List _options = []; private Type? _customViewType; - internal PluginSettingsSectionBuilder( + internal AirAppSettingsSectionBuilder( string id, string titleLocalizationKey, string? descriptionLocalizationKey, @@ -35,17 +35,17 @@ public sealed class PluginSettingsSectionBuilder public Type? CustomViewType => _customViewType; - public IReadOnlyList Options => _options; + public IReadOnlyList Options => _options; /// /// Sets a custom AXAML view for this settings section. - /// The view type must be a subclass of . + /// The view type must be a subclass of . /// When a custom view is provided, the host application will use it directly /// instead of generating a page from the declared options, allowing the plugin /// to use any Fluent Avalonia controls and custom layouts. /// - /// A subclass that defines the settings UI. - public PluginSettingsSectionBuilder SetCustomView() where TView : SettingsPageBase + /// A subclass that defines the settings UI. + public AirAppSettingsSectionBuilder SetCustomView() where TView : AirAppSettingsPageBase { _customViewType = typeof(TView); return this; @@ -53,19 +53,19 @@ public sealed class PluginSettingsSectionBuilder /// /// Sets a custom AXAML view for this settings section. - /// The view type must be a subclass of . + /// The view type must be a subclass of . /// When a custom view is provided, the host application will use it directly /// instead of generating a page from the declared options. /// - /// A subclass type that defines the settings UI. - public PluginSettingsSectionBuilder SetCustomView(Type viewType) + /// A subclass type that defines the settings UI. + public AirAppSettingsSectionBuilder SetCustomView(Type viewType) { ArgumentNullException.ThrowIfNull(viewType); - if (!typeof(SettingsPageBase).IsAssignableFrom(viewType)) + if (!typeof(AirAppSettingsPageBase).IsAssignableFrom(viewType)) { throw new ArgumentException( - $"Custom view type must be a subclass of {nameof(SettingsPageBase)}.", + $"Custom view type must be a subclass of {nameof(AirAppSettingsPageBase)}.", nameof(viewType)); } @@ -73,44 +73,44 @@ public sealed class PluginSettingsSectionBuilder return this; } - public PluginSettingsSectionBuilder AddOption(SettingsOptionDefinition option) + public AirAppSettingsSectionBuilder AddOption(AirAppSettingOptionDefinition option) { ArgumentNullException.ThrowIfNull(option); _options.Add(option); return this; } - public PluginSettingsSectionBuilder AddToggle( + public AirAppSettingsSectionBuilder AddToggle( string key, string titleLocalizationKey, string? descriptionLocalizationKey = null, bool defaultValue = false) { - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.Toggle, + AirAppSettingOptionType.Toggle, titleLocalizationKey, descriptionLocalizationKey, defaultValue)); } - public PluginSettingsSectionBuilder AddText( + public AirAppSettingsSectionBuilder AddText( string key, string titleLocalizationKey, string? descriptionLocalizationKey = null, string defaultValue = "", string? validationPattern = null) { - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.Text, + AirAppSettingOptionType.Text, titleLocalizationKey, descriptionLocalizationKey, defaultValue, validationPattern: validationPattern)); } - public PluginSettingsSectionBuilder AddNumber( + public AirAppSettingsSectionBuilder AddNumber( string key, string titleLocalizationKey, string? descriptionLocalizationKey = null, @@ -118,9 +118,9 @@ public sealed class PluginSettingsSectionBuilder double? minimum = null, double? maximum = null) { - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.Number, + AirAppSettingOptionType.Number, titleLocalizationKey, descriptionLocalizationKey, defaultValue, @@ -128,56 +128,56 @@ public sealed class PluginSettingsSectionBuilder maximum: maximum)); } - public PluginSettingsSectionBuilder AddSelect( + public AirAppSettingsSectionBuilder AddSelect( string key, string titleLocalizationKey, - IEnumerable choices, + IEnumerable choices, string? descriptionLocalizationKey = null, string? defaultValue = null) { ArgumentNullException.ThrowIfNull(choices); var normalizedChoices = choices.ToArray(); - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.Select, + AirAppSettingOptionType.Select, titleLocalizationKey, descriptionLocalizationKey, defaultValue, normalizedChoices)); } - public PluginSettingsSectionBuilder AddPath( + public AirAppSettingsSectionBuilder AddPath( string key, string titleLocalizationKey, string? descriptionLocalizationKey = null, string defaultValue = "") { - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.Path, + AirAppSettingOptionType.Path, titleLocalizationKey, descriptionLocalizationKey, defaultValue)); } - public PluginSettingsSectionBuilder AddList( + public AirAppSettingsSectionBuilder AddList( string key, string titleLocalizationKey, string? descriptionLocalizationKey = null, IReadOnlyList? defaultValue = null) { - return AddOption(new SettingsOptionDefinition( + return AddOption(new AirAppSettingOptionDefinition( key, - SettingsOptionType.List, + AirAppSettingOptionType.List, titleLocalizationKey, descriptionLocalizationKey, defaultValue ?? Array.Empty())); } - internal PluginSettingsSectionRegistration Build() + internal AirAppSettingsSectionRegistration Build() { - return new PluginSettingsSectionRegistration( + return new AirAppSettingsSectionRegistration( Id, TitleLocalizationKey, _options.ToArray(), diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsSectionDefinition.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionDefinition.cs similarity index 78% rename from airapp/LanMountainDesktop.PluginSdk/SettingsSectionDefinition.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionDefinition.cs index 7143fbd..7853800 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsSectionDefinition.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionDefinition.cs @@ -1,19 +1,19 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class SettingsSectionDefinition +public sealed class AirAppSettingsSectionDefinition { - public SettingsSectionDefinition( + public AirAppSettingsSectionDefinition( string id, string category, - SettingsScope scope, + AirAppSettingsScope scope, string titleLocalizationKey, string? descriptionLocalizationKey = null, string iconKey = "Settings", int sortOrder = 0, string? subjectId = null, - IReadOnlyList? options = null) + IReadOnlyList? options = null) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentException.ThrowIfNullOrWhiteSpace(category); @@ -37,7 +37,7 @@ public sealed class SettingsSectionDefinition public string Category { get; } - public SettingsScope Scope { get; } + public AirAppSettingsScope Scope { get; } public string TitleLocalizationKey { get; } @@ -49,5 +49,5 @@ public sealed class SettingsSectionDefinition public string? SubjectId { get; } - public IReadOnlyList Options { get; } + public IReadOnlyList Options { get; } } diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionRegistration.cs similarity index 77% rename from airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionRegistration.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionRegistration.cs index 4516d9d..9bcf1ce 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginSettingsSectionRegistration.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSettingsSectionRegistration.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed class PluginSettingsSectionRegistration +public sealed class AirAppSettingsSectionRegistration { - public PluginSettingsSectionRegistration( + public AirAppSettingsSectionRegistration( string id, string titleLocalizationKey, - IReadOnlyList options, + IReadOnlyList options, string? descriptionLocalizationKey = null, string iconKey = "PuzzlePiece", int sortOrder = 0, @@ -27,10 +27,10 @@ public sealed class PluginSettingsSectionRegistration SortOrder = sortOrder; Options = options ?? []; - if (customViewType is not null && !typeof(SettingsPageBase).IsAssignableFrom(customViewType)) + if (customViewType is not null && !typeof(AirAppSettingsPageBase).IsAssignableFrom(customViewType)) { throw new ArgumentException( - $"Custom view type must be a subclass of {nameof(SettingsPageBase)}.", + $"Custom view type must be a subclass of {nameof(AirAppSettingsPageBase)}.", nameof(customViewType)); } @@ -47,10 +47,10 @@ public sealed class PluginSettingsSectionRegistration public int SortOrder { get; } - public IReadOnlyList Options { get; } + public IReadOnlyList Options { get; } /// - /// When set, the host application will instantiate this subclass + /// When set, the host application will instantiate this subclass /// instead of generating a page from . /// This allows plugins to provide fully custom AXAML views with any Fluent Avalonia controls. /// diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginSharedContractReference.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppSharedContractReference.cs similarity index 80% rename from airapp/LanMountainDesktop.PluginSdk/PluginSharedContractReference.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppSharedContractReference.cs index 43e5095..4af9597 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginSharedContractReference.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppSharedContractReference.cs @@ -1,8 +1,8 @@ using System.Text.Json.Serialization; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public sealed record PluginSharedContractReference( +public sealed record AirAppSharedContractReference( string Id, string Version, string AssemblyName) @@ -16,7 +16,7 @@ public sealed record PluginSharedContractReference( [JsonIgnore] public string NormalizedAssemblyName => AssemblyName.Trim(); - internal PluginSharedContractReference NormalizeAndValidate(string manifestPath) + internal AirAppSharedContractReference NormalizeAndValidate(string manifestPath) { var normalized = this with { @@ -28,7 +28,7 @@ public sealed record PluginSharedContractReference( if (!System.Version.TryParse(normalized.Version, out _)) { throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' declares invalid shared contract version '{normalized.Version}' for '{normalized.Id}'."); + $"AirApp manifest '{manifestPath}' declares invalid shared contract version '{normalized.Version}' for '{normalized.Id}'."); } return normalized; @@ -39,7 +39,7 @@ public sealed record PluginSharedContractReference( if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' is missing required shared contract property '{propertyName}'."); + $"AirApp manifest '{manifestPath}' is missing required shared contract property '{propertyName}'."); } return value.Trim(); diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppWidgetBase.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWidgetBase.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppWidgetBase.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppWidgetBase.cs diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowBase.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowBase.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowBase.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppWindowBase.cs diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowChromeMode.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowChromeMode.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowChromeMode.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppWindowChromeMode.cs diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowDescriptor.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowDescriptor.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/AirAppWindowDescriptor.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppWindowDescriptor.cs diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowRegistration.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowRegistration.cs new file mode 100644 index 0000000..bd94065 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppWindowRegistration.cs @@ -0,0 +1,11 @@ +namespace LanMountainDesktop.AirAppSdk; + +/// +/// Describes a window entry contributed by an AirApp. +/// Produced by AddAirAppWindow<TWindow> and resolved by the AirAppHost +/// window loader to open the window content inside the host window shell. +/// +public sealed record AirAppWindowRegistration( + string WindowId, + string DisplayName, + Type WindowType); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginWorkerBase.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerBase.cs similarity index 61% rename from airapp/LanMountainDesktop.PluginSdk/PluginWorkerBase.cs rename to airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerBase.cs index f3c5418..5cbccb3 100644 --- a/airapp/LanMountainDesktop.PluginSdk/PluginWorkerBase.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerBase.cs @@ -1,14 +1,14 @@ using Microsoft.Extensions.DependencyInjection; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public abstract class PluginWorkerBase : IPluginWorker +public abstract class AirAppWorkerBase : IAirAppWorker { - public virtual void ConfigureServices(IPluginWorkerContext context, IServiceCollection services) + public virtual void ConfigureServices(IAirAppWorkerContext context, IServiceCollection services) { } - public virtual Task StartAsync(IPluginWorkerContext context, IServiceProvider services, CancellationToken cancellationToken = default) + public virtual Task StartAsync(IAirAppWorkerContext context, IServiceProvider services, CancellationToken cancellationToken = default) { return Task.CompletedTask; } diff --git a/airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerEntranceAttribute.cs b/airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerEntranceAttribute.cs new file mode 100644 index 0000000..f3f1296 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/AirAppWorkerEntranceAttribute.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppSdk; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public sealed class AirAppWorkerEntranceAttribute : Attribute +{ +} diff --git a/airapp/LanMountainDesktop.PluginSdk/AppearanceChangedEvent.cs b/airapp/LanMountainDesktop.AirAppSdk/AppearanceChangedEvent.cs similarity index 93% rename from airapp/LanMountainDesktop.PluginSdk/AppearanceChangedEvent.cs rename to airapp/LanMountainDesktop.AirAppSdk/AppearanceChangedEvent.cs index 244bb55..50da9b3 100644 --- a/airapp/LanMountainDesktop.PluginSdk/AppearanceChangedEvent.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AppearanceChangedEvent.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; /// /// Provides the latest read-only appearance snapshot when host appearance values change. @@ -6,7 +6,7 @@ namespace LanMountainDesktop.PluginSdk; public sealed class AppearanceChangedEvent : EventArgs { public AppearanceChangedEvent( - PluginAppearanceSnapshot snapshot, + AirAppAppearanceSnapshot snapshot, IReadOnlyCollection changedProperties) { ArgumentNullException.ThrowIfNull(snapshot); @@ -16,7 +16,7 @@ public sealed class AppearanceChangedEvent : EventArgs ChangedProperties = changedProperties; } - public PluginAppearanceSnapshot Snapshot { get; } + public AirAppAppearanceSnapshot Snapshot { get; } public IReadOnlyCollection ChangedProperties { get; } diff --git a/airapp/LanMountainDesktop.PluginSdk/AppearanceContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/AppearanceContracts.cs similarity index 72% rename from airapp/LanMountainDesktop.PluginSdk/AppearanceContracts.cs rename to airapp/LanMountainDesktop.AirAppSdk/AppearanceContracts.cs index 45e64d0..eeaeea1 100644 --- a/airapp/LanMountainDesktop.PluginSdk/AppearanceContracts.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AppearanceContracts.cs @@ -1,12 +1,12 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; /// /// Wire request for the IPC appearance snapshot payload. This request targets the /// isolation-contract DTOs, not the runtime SDK snapshot with the same type name. /// -public sealed record PluginAppearanceSnapshotRequest(string SessionId); +public sealed record AirAppAppearanceSnapshotRequest(string SessionId); -public sealed record PluginMaterialSurfaceSnapshot( +public sealed record AirAppMaterialSurfaceSnapshot( string BackgroundColor, string BorderColor, double BlurRadius, @@ -14,9 +14,9 @@ public sealed record PluginMaterialSurfaceSnapshot( /// /// Wire-format appearance snapshot exchanged over IPC. -/// Do not treat this as the same type as LanMountainDesktop.PluginSdk.PluginAppearanceSnapshot. +/// Do not treat this as the same type as LanMountainDesktop.AirAppSdk.AirAppAppearanceSnapshot. /// -public sealed record PluginAppearanceSnapshot( +public sealed record AirAppAppearanceSnapshot( string ThemeVariant, string? AccentColor = null, double CornerRadiusScale = 1.0, @@ -26,10 +26,10 @@ public sealed record PluginAppearanceSnapshot( string? ColorSource = null, string? SystemMaterialMode = null, IReadOnlyDictionary? ColorRoles = null, - IReadOnlyDictionary? MaterialSurfaces = null, + IReadOnlyDictionary? MaterialSurfaces = null, IReadOnlyList? WallpaperSeedCandidates = null); /// /// Wire notification carrying the IPC appearance snapshot. /// -public sealed record PluginAppearanceChangedNotification(PluginAppearanceSnapshot Snapshot); +public sealed record AirAppAppearanceChangedNotification(AirAppAppearanceSnapshot Snapshot); diff --git a/airapp/LanMountainDesktop.PluginSdk/AppearanceCornerRadiusTokenFactory.cs b/airapp/LanMountainDesktop.AirAppSdk/AppearanceCornerRadiusTokenFactory.cs similarity index 96% rename from airapp/LanMountainDesktop.PluginSdk/AppearanceCornerRadiusTokenFactory.cs rename to airapp/LanMountainDesktop.AirAppSdk/AppearanceCornerRadiusTokenFactory.cs index be4f25c..0c94510 100644 --- a/airapp/LanMountainDesktop.PluginSdk/AppearanceCornerRadiusTokenFactory.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AppearanceCornerRadiusTokenFactory.cs @@ -1,8 +1,8 @@ using Avalonia; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts; -namespace LanMountainDesktop.Appearance; +namespace LanMountainDesktop.AirAppSdk; public static class AppearanceCornerRadiusTokenFactory { diff --git a/airapp/LanMountainDesktop.PluginSdk/AssemblyInfo.cs b/airapp/LanMountainDesktop.AirAppSdk/AssemblyInfo.cs similarity index 80% rename from airapp/LanMountainDesktop.PluginSdk/AssemblyInfo.cs rename to airapp/LanMountainDesktop.AirAppSdk/AssemblyInfo.cs index d4b42b7..cfc54a7 100644 --- a/airapp/LanMountainDesktop.PluginSdk/AssemblyInfo.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/AssemblyInfo.cs @@ -1,4 +1,4 @@ using Avalonia.Metadata; [assembly: XmlnsPrefix("http://lanmountain.tech/schemas/xaml/sdk", "lmd")] -[assembly: XmlnsDefinition("http://lanmountain.tech/schemas/xaml/sdk", "LanMountainDesktop.PluginSdk")] +[assembly: XmlnsDefinition("http://lanmountain.tech/schemas/xaml/sdk", "LanMountainDesktop.AirAppSdk")] diff --git a/airapp/LanMountainDesktop.PluginSdk/DiagnosticsContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/DiagnosticsContracts.cs similarity index 78% rename from airapp/LanMountainDesktop.PluginSdk/DiagnosticsContracts.cs rename to airapp/LanMountainDesktop.AirAppSdk/DiagnosticsContracts.cs index 7a5b9b1..5b0a4c4 100644 --- a/airapp/LanMountainDesktop.PluginSdk/DiagnosticsContracts.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/DiagnosticsContracts.cs @@ -1,21 +1,21 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public sealed record PluginHeartbeatPing( +public sealed record AirAppHeartbeatPing( string SessionId, DateTimeOffset SentAtUtc); -public sealed record PluginHeartbeatPong( +public sealed record AirAppHeartbeatPong( string SessionId, DateTimeOffset ReceivedAtUtc); -public sealed record PluginLogEntry( +public sealed record AirAppLogEntry( string Level, string Category, string Message, DateTimeOffset TimestampUtc, string? Exception = null); -public static class PluginLogLevels +public static class AirAppLogLevels { public const string Trace = "trace"; public const string Debug = "debug"; @@ -25,7 +25,7 @@ public static class PluginLogLevels public const string Critical = "critical"; } -public sealed record PluginFaultReport( +public sealed record AirAppFaultReport( string SessionId, string FaultKind, bool IsFatal, @@ -35,7 +35,7 @@ public sealed record PluginFaultReport( int? ExitCode = null, DateTimeOffset? OccurredAtUtc = null); -public static class PluginFaultKinds +public static class AirAppFaultKinds { public const string ManagedException = "managed-exception"; public const string NativeCrash = "native-crash"; diff --git a/airapp/LanMountainDesktop.PluginSdk/GlobalAppearanceSettings.cs b/airapp/LanMountainDesktop.AirAppSdk/GlobalAppearanceSettings.cs similarity index 98% rename from airapp/LanMountainDesktop.PluginSdk/GlobalAppearanceSettings.cs rename to airapp/LanMountainDesktop.AirAppSdk/GlobalAppearanceSettings.cs index 28999ea..0b81b86 100644 --- a/airapp/LanMountainDesktop.PluginSdk/GlobalAppearanceSettings.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/GlobalAppearanceSettings.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.Settings.Core; +namespace LanMountainDesktop.AirAppSdk; public static class GlobalAppearanceSettings { diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirApp.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirApp.cs similarity index 79% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirApp.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirApp.cs index 6d05f33..c58d2e6 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/IAirApp.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirApp.cs @@ -4,7 +4,10 @@ using Microsoft.Extensions.Hosting; namespace LanMountainDesktop.AirAppSdk; /// -/// Core interface for AirApp entry point. +/// Core interface for the AirApp entry point. +/// Implement this interface (or derive from ) and mark the class +/// with to expose a desktop component or window +/// AirApp to the LanMountainDesktop host. /// public interface IAirApp { diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginAppearanceContext.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs similarity index 85% rename from airapp/LanMountainDesktop.PluginSdk/IPluginAppearanceContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs index 73986e8..c83e9b9 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginAppearanceContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs @@ -1,14 +1,14 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; /// /// 插件外观上下文接口,提供主题、圆角等外观资源的访问和变更通知。 /// -public interface IPluginAppearanceContext +public interface IAirAppAppearanceContext { /// /// 当前外观快照。 /// - PluginAppearanceSnapshot Snapshot { get; } + AirAppAppearanceSnapshot Snapshot { get; } /// /// 外观变更事件。当主题、圆角或其他外观属性发生变化时触发。 @@ -31,5 +31,5 @@ public interface IPluginAppearanceContext /// 最小值(可选) /// 最大值(可选) /// 解析后的圆角半径 - double ResolveCornerRadius(PluginCornerRadiusPreset preset, double? minimum = null, double? maximum = null); + double ResolveCornerRadius(AirAppCornerRadiusPreset preset, double? minimum = null, double? maximum = null); } diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppComponentContext.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppComponentContext.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppComponentContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppComponentContext.cs diff --git a/airapp/LanMountainDesktop.AirAppSdk/IAirAppExportRegistry.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppExportRegistry.cs new file mode 100644 index 0000000..df7aa2f --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppExportRegistry.cs @@ -0,0 +1,13 @@ +namespace LanMountainDesktop.AirAppSdk; + +public interface IAirAppExportRegistry +{ + IReadOnlyList GetExports(); + + IReadOnlyList GetExports(Type contractType); + + AirAppServiceExportDescriptor? GetExport(Type contractType, string providerAirAppId); + + TContract? GetExport(string providerAirAppId) + where TContract : class; +} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppLogger.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppLogger.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppLogger.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppLogger.cs diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs similarity index 71% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs index 317d3fb..b9db56b 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppMessageBus.cs @@ -2,9 +2,20 @@ namespace LanMountainDesktop.AirAppSdk; /// /// Message bus for inter-AirApp communication. +/// Supports both strong-typed messages and topic-based routing. /// public interface IAirAppMessageBus { + /// + /// Subscribe to a strong-typed message. + /// + IDisposable Subscribe(Action handler); + + /// + /// Publish a strong-typed message. + /// + void Publish(TMessage message); + /// /// Publish a message to a topic. /// @@ -21,7 +32,7 @@ public interface IAirAppMessageBus IDisposable Subscribe(string topic, Action handler); /// - /// Subscribe to a topic with typed payload. + /// Subscribe to a topic with a typed payload. /// /// Payload type /// Message topic diff --git a/airapp/LanMountainDesktop.AirAppSdk/IAirAppPackageManager.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPackageManager.cs new file mode 100644 index 0000000..461878c --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPackageManager.cs @@ -0,0 +1,8 @@ +namespace LanMountainDesktop.AirAppSdk; + +public interface IAirAppPackageManager +{ + IReadOnlyList GetInstalledAirApps(); + + AirAppPackageInstallResult InstallPackage(string packagePath); +} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcBuilder.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcBuilder.cs similarity index 60% rename from airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcBuilder.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcBuilder.cs index 1167944..0a1c4ad 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcBuilder.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcBuilder.cs @@ -1,13 +1,13 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public interface IPluginPublicIpcBuilder +public interface IAirAppPublicIpcBuilder { - IPluginPublicIpcBuilder AddService( + IAirAppPublicIpcBuilder AddService( string? objectId = null, IEnumerable? notifyIds = null) where TContract : class; - IPluginPublicIpcBuilder AddService( + IAirAppPublicIpcBuilder AddService( Type contractType, object implementation, string? objectId = null, diff --git a/airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcContributor.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcContributor.cs new file mode 100644 index 0000000..708ea96 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppPublicIpcContributor.cs @@ -0,0 +1,6 @@ +namespace LanMountainDesktop.AirAppSdk; + +public interface IAirAppPublicIpcContributor +{ + void ConfigurePublicIpc(IAirAppPublicIpcBuilder builder); +} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs similarity index 69% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs index 66e785e..76393ed 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppRuntimeContext.cs @@ -4,23 +4,20 @@ namespace LanMountainDesktop.AirAppSdk; /// /// Provides runtime context and services for an AirApp. +/// The host hands an implementation to and exposes it +/// through the per-AirApp service container. /// public interface IAirAppRuntimeContext { /// - /// Gets the unique identifier of this AirApp. + /// Gets the manifest of this AirApp. /// - string AirAppId { get; } + AirAppManifest Manifest { get; } /// - /// Gets the display name of this AirApp. + /// Gets the directory that contains the loaded AirApp package. /// - string AirAppName { get; } - - /// - /// Gets the AirApp version. - /// - string AirAppVersion { get; } + string AirAppDirectory { get; } /// /// Gets the data directory for this AirApp. @@ -39,6 +36,11 @@ public interface IAirAppRuntimeContext /// IServiceProvider Services { get; } + /// + /// Gets a snapshot of the host-provided properties for this AirApp. + /// + IReadOnlyDictionary Properties { get; } + /// /// Gets the host application lifetime manager. /// @@ -59,6 +61,16 @@ public interface IAirAppRuntimeContext /// IAirAppLogger Logger { get; } + /// + /// Resolve a service from the AirApp service provider. + /// + T? GetService(); + + /// + /// Try to read a host-provided property. + /// + bool TryGetProperty(string key, out T? value); + /// /// Opens a window defined by this AirApp. /// @@ -73,17 +85,17 @@ public interface IAirAppRuntimeContext void CloseWindow(string windowId); /// - /// Register a desktop component (internal use by AirAppBase). + /// Register a desktop component (internal use by ). /// void RegisterComponent(AirAppComponentOptions options); /// - /// Register a window (internal use by AirAppBase). + /// Register a window (internal use by ). /// void RegisterWindow(string id, string name, Type windowType); /// - /// Register a service (internal use by AirAppBase). + /// Register a service (internal use by ). /// void RegisterService() where TService : class diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginSettingsService.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppSettingsService.cs similarity index 82% rename from airapp/LanMountainDesktop.PluginSdk/IPluginSettingsService.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppSettingsService.cs index 640fd64..af5ec0f 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginSettingsService.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppSettingsService.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public interface IPluginSettingsService +public interface IAirAppSettingsService { - string PluginId { get; } + string AirAppId { get; } IComponentSettingsAccessor GetComponentAccessor(string componentId, string? placementId); diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppWidget.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWidget.cs similarity index 100% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppWidget.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppWidget.cs diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs similarity index 76% rename from airappsdk/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs index 56e1e51..3e2b6fd 100644 --- a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWindow.cs @@ -12,6 +12,13 @@ public interface IAirAppWindow /// AirAppWindowDescriptor Descriptor { get; } + /// + /// Gets the root content hosted inside the AirAppHost window shell. + /// inherits from Avalonia Window and satisfies this + /// through Window.Content. + /// + object? Content { get; } + /// /// Called before the window is opened. /// Use this for async initialization. diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginWorker.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWorker.cs similarity index 50% rename from airapp/LanMountainDesktop.PluginSdk/IPluginWorker.cs rename to airapp/LanMountainDesktop.AirAppSdk/IAirAppWorker.cs index 32fee7b..12ad0a7 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginWorker.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWorker.cs @@ -1,12 +1,12 @@ using Microsoft.Extensions.DependencyInjection; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; -public interface IPluginWorker +public interface IAirAppWorker { - void ConfigureServices(IPluginWorkerContext context, IServiceCollection services); + void ConfigureServices(IAirAppWorkerContext context, IServiceCollection services); - Task StartAsync(IPluginWorkerContext context, IServiceProvider services, CancellationToken cancellationToken = default); + Task StartAsync(IAirAppWorkerContext context, IServiceProvider services, CancellationToken cancellationToken = default); Task StopAsync(CancellationToken cancellationToken = default); } diff --git a/airapp/LanMountainDesktop.AirAppSdk/IAirAppWorkerContext.cs b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWorkerContext.cs new file mode 100644 index 0000000..db48a80 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/IAirAppWorkerContext.cs @@ -0,0 +1,26 @@ +using LanMountainDesktop.AirAppIsolation.Contracts; + +namespace LanMountainDesktop.AirAppSdk; + +public interface IAirAppWorkerContext +{ + string AirAppId { get; } + + AirAppManifest Manifest { get; } + + AirAppRuntimeMode RuntimeMode { get; } + + string SessionId { get; } + + string HostPipeName { get; } + + string ProtocolVersion { get; } + + string AirAppDirectory { get; } + + string DataDirectory { get; } + + IReadOnlyList GrantedCapabilities { get; } + + IReadOnlyDictionary StartupProperties { get; } +} diff --git a/airapp/LanMountainDesktop.PluginSdk/IComponentEditorHostContext.cs b/airapp/LanMountainDesktop.AirAppSdk/IComponentEditorHostContext.cs similarity index 79% rename from airapp/LanMountainDesktop.PluginSdk/IComponentEditorHostContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/IComponentEditorHostContext.cs index 74dd7dc..9e3175f 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IComponentEditorHostContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IComponentEditorHostContext.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public interface IComponentEditorHostContext { diff --git a/airapp/LanMountainDesktop.PluginSdk/IComponentSettingsAccessor.cs b/airapp/LanMountainDesktop.AirAppSdk/IComponentSettingsAccessor.cs similarity index 93% rename from airapp/LanMountainDesktop.PluginSdk/IComponentSettingsAccessor.cs rename to airapp/LanMountainDesktop.AirAppSdk/IComponentSettingsAccessor.cs index 41f9788..865d5b1 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IComponentSettingsAccessor.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IComponentSettingsAccessor.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public interface IComponentSettingsAccessor { diff --git a/airapp/LanMountainDesktop.PluginSdk/IDesktopShellHost.cs b/airapp/LanMountainDesktop.AirAppSdk/IDesktopShellHost.cs similarity index 56% rename from airapp/LanMountainDesktop.PluginSdk/IDesktopShellHost.cs rename to airapp/LanMountainDesktop.AirAppSdk/IDesktopShellHost.cs index cf5743a..aa271c9 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IDesktopShellHost.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IDesktopShellHost.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.Host.Abstractions; +namespace LanMountainDesktop.AirAppSdk; public interface IDesktopShellHost { diff --git a/airapp/LanMountainDesktop.PluginSdk/IHostApplicationLifecycle.cs b/airapp/LanMountainDesktop.AirAppSdk/IHostApplicationLifecycle.cs similarity index 88% rename from airapp/LanMountainDesktop.PluginSdk/IHostApplicationLifecycle.cs rename to airapp/LanMountainDesktop.AirAppSdk/IHostApplicationLifecycle.cs index cbd3817..e9cc10d 100644 --- a/airapp/LanMountainDesktop.PluginSdk/IHostApplicationLifecycle.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/IHostApplicationLifecycle.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public sealed record HostApplicationLifecycleRequest( string? Source = null, diff --git a/airapp/LanMountainDesktop.AirAppSdk/ISettingsCatalog.cs b/airapp/LanMountainDesktop.AirAppSdk/ISettingsCatalog.cs new file mode 100644 index 0000000..deebd95 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/ISettingsCatalog.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace LanMountainDesktop.AirAppSdk; + +public interface ISettingsCatalog +{ + IReadOnlyList GetSections(); + + IReadOnlyList GetSections(AirAppSettingsScope scope); +} diff --git a/airapp/LanMountainDesktop.PluginSdk/ISettingsPageHostContext.cs b/airapp/LanMountainDesktop.AirAppSdk/ISettingsPageHostContext.cs similarity index 83% rename from airapp/LanMountainDesktop.PluginSdk/ISettingsPageHostContext.cs rename to airapp/LanMountainDesktop.AirAppSdk/ISettingsPageHostContext.cs index fc4ad36..269a1f8 100644 --- a/airapp/LanMountainDesktop.PluginSdk/ISettingsPageHostContext.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/ISettingsPageHostContext.cs @@ -1,6 +1,6 @@ using Avalonia.Controls; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public interface ISettingsPageHostContext { diff --git a/airapp/LanMountainDesktop.PluginSdk/ISettingsService.cs b/airapp/LanMountainDesktop.AirAppSdk/ISettingsService.cs similarity index 76% rename from airapp/LanMountainDesktop.PluginSdk/ISettingsService.cs rename to airapp/LanMountainDesktop.AirAppSdk/ISettingsService.cs index 0c9ede1..038bf1d 100644 --- a/airapp/LanMountainDesktop.PluginSdk/ISettingsService.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/ISettingsService.cs @@ -1,15 +1,15 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public interface ISettingsService { event EventHandler? Changed; - T LoadSnapshot(SettingsScope scope, string? subjectId = null, string? placementId = null) where T : new(); + T LoadSnapshot(AirAppSettingsScope scope, string? subjectId = null, string? placementId = null) where T : new(); void SaveSnapshot( - SettingsScope scope, + AirAppSettingsScope scope, T snapshot, string? subjectId = null, string? placementId = null, @@ -17,13 +17,13 @@ public interface ISettingsService IReadOnlyCollection? changedKeys = null); T LoadSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null) where T : new(); void SaveSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, T section, @@ -31,20 +31,20 @@ public interface ISettingsService IReadOnlyCollection? changedKeys = null); void DeleteSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null); T? GetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, string? subjectId = null, string? placementId = null, string? sectionId = null); void SetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, T value, string? subjectId = null, diff --git a/airapp/LanMountainDesktop.PluginSdk/InProcPluginIpcTransport.cs b/airapp/LanMountainDesktop.AirAppSdk/InProcAirAppIpcTransport.cs similarity index 75% rename from airapp/LanMountainDesktop.PluginSdk/InProcPluginIpcTransport.cs rename to airapp/LanMountainDesktop.AirAppSdk/InProcAirAppIpcTransport.cs index a5a414d..caf1a3f 100644 --- a/airapp/LanMountainDesktop.PluginSdk/InProcPluginIpcTransport.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/InProcAirAppIpcTransport.cs @@ -1,17 +1,17 @@ -namespace LanMountainDesktop.PluginIsolation.Ipc; +namespace LanMountainDesktop.AirAppIsolation.Ipc; /// -/// 进程内 IPC 传输。将 的调度委托直接绑定到 -/// 的处理入口,不经过命名管道。 +/// 进程内 IPC 传输。将 的调度委托直接绑定到 +/// 的处理入口,不经过命名管道。 /// 用于不支持子进程/命名管道的平台(如 Android),插件契约与序列化路径保持不变: /// 请求仍会经过 JsonElement 序列化/反序列化边界,与管道传输行为一致。 /// -public sealed class InProcPluginIpcTransport : IDisposable +public sealed class InProcAirAppIpcTransport : IDisposable { - private readonly PluginIpcClient _client; + private readonly AirAppIpcClient _client; private volatile bool _disposed; - private InProcPluginIpcTransport(PluginIpcClient client, PluginIpcServer server) + private InProcAirAppIpcTransport(AirAppIpcClient client, AirAppIpcServer server) { _client = client; Server = server; @@ -32,12 +32,12 @@ public sealed class InProcPluginIpcTransport : IDisposable /// /// 绑定后的服务端。 /// - public PluginIpcServer Server { get; } + public AirAppIpcServer Server { get; } /// /// 绑定后的客户端。请求/通知将直接分发到 。 /// - public PluginIpcClient Client => _client; + public AirAppIpcClient Client => _client; /// /// 将客户端与服务端以进程内直通方式连接。 @@ -45,11 +45,11 @@ public sealed class InProcPluginIpcTransport : IDisposable /// 插件侧客户端 /// 宿主侧服务端 /// 传输句柄;Dispose 后客户端调度将抛出 - public static InProcPluginIpcTransport Connect(PluginIpcClient client, PluginIpcServer server) + public static InProcAirAppIpcTransport Connect(AirAppIpcClient client, AirAppIpcServer server) { ArgumentNullException.ThrowIfNull(client); ArgumentNullException.ThrowIfNull(server); - return new InProcPluginIpcTransport(client, server); + return new InProcAirAppIpcTransport(client, server); } /// diff --git a/airapp/LanMountainDesktop.AirAppSdk/LICENSE b/airapp/LanMountainDesktop.AirAppSdk/LICENSE new file mode 100644 index 0000000..107c638 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) LanMountainDesktop Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/airapp/LanMountainDesktop.PluginSdk/LanMountainDesktop.PluginSdk.csproj b/airapp/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj similarity index 68% rename from airapp/LanMountainDesktop.PluginSdk/LanMountainDesktop.PluginSdk.csproj rename to airapp/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj index 35a02d6..b940a88 100644 --- a/airapp/LanMountainDesktop.PluginSdk/LanMountainDesktop.PluginSdk.csproj +++ b/airapp/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj @@ -4,16 +4,16 @@ net10.0 enable enable - 6.0.0 - LanMountainDesktop.PluginSdk + 1.0.0 + LanMountainDesktop.AirAppSdk true LanMountainDesktop - Official plugin SDK for LanMountainDesktop, including plugin manifest contracts, runtime interfaces, and registration extensions. - LanMountainDesktop;Plugin;SDK;Avalonia + Official AirApp (Lightweight Application) SDK for LanMountainDesktop. Develop desktop components and window apps for the LanMountainDesktop extension ecosystem. + LanMountainDesktop;AirApp;SDK;Avalonia;Plugin README.md https://github.com/wwiinnddyy/LanMountainDesktop git - LGPL-3.0-or-later + MIT Copyright (c) LanMountainDesktop Contributors @@ -30,8 +30,9 @@ - - + + + diff --git a/airapp/LanMountainDesktop.PluginSdk/LifecycleContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/LifecycleContracts.cs similarity index 62% rename from airapp/LanMountainDesktop.PluginSdk/LifecycleContracts.cs rename to airapp/LanMountainDesktop.AirAppSdk/LifecycleContracts.cs index ad821ab..b734d32 100644 --- a/airapp/LanMountainDesktop.PluginSdk/LifecycleContracts.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/LifecycleContracts.cs @@ -1,28 +1,28 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public sealed record PluginInitializeRequest( - string PluginId, +public sealed record AirAppInitializeRequest( + string AirAppId, string SessionId, string HostPipeName, string DataDirectory, IReadOnlyDictionary? StartupProperties = null); -public sealed record PluginInitializeResponse( +public sealed record AirAppInitializeResponse( bool Succeeded, string? ErrorCode = null, string? ErrorMessage = null); -public sealed record PluginStopRequest( +public sealed record AirAppStopRequest( string Reason, bool RestartRequested = false); -public sealed record PluginRestartRequest(string Reason); +public sealed record AirAppRestartRequest(string Reason); -public sealed record PluginLifecycleStateChanged( +public sealed record AirAppLifecycleStateChanged( string State, string? Detail = null); -public static class PluginLifecycleStates +public static class AirAppLifecycleStates { public const string Starting = "starting"; public const string Ready = "ready"; diff --git a/airapp/LanMountainDesktop.AirAppSdk/README.md b/airapp/LanMountainDesktop.AirAppSdk/README.md new file mode 100644 index 0000000..c4051f0 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/README.md @@ -0,0 +1,39 @@ +# LanMountainDesktop.AirAppSdk + +Official AirApp (Lightweight Application) SDK for LanMountainDesktop. + +AirApp is the unified extension system for LanMountainDesktop. Developers use this SDK to build +**desktop components** (rendered in the host process on the desktop grid) and **window AirApps** +(hosted in the isolated `AirAppHost` process). + +## Includes + +- `IAirApp` / `AirAppBase` entry abstractions with `[AirAppEntrance]` +- `IAirAppWorker` / `AirAppWorkerBase` worker-side entry abstractions for isolated background mode +- `AirAppManifest` (`airapp.json`) and shared contract declarations +- `runtime.mode` manifest support for `in-process`, `isolated-background`, and `isolated-window` +- Desktop component registration (`AddAirAppComponent`) and window registration (`AddAirAppWindow`) +- Declarative and custom settings sections (`AddAirAppSettingsSection`) +- Runtime context, appearance, settings, message bus, logger and host service abstractions +- Build-transitive packaging targets for `.laapp` output + +## Quick Start + +Install the template and create an AirApp project: + +```bash +dotnet new install LanMountainDesktop.AirAppTemplate +dotnet new lmd-airapp -n MyAirApp +``` + +Or reference the package directly: + +```xml + + + +``` + +Create `airapp.json` in your AirApp project root, then run `dotnet build` to produce both build +output and a `.laapp` package. Install the `.laapp` package into LanMountainDesktop to load your +AirApp. diff --git a/airapp/LanMountainDesktop.AirAppSdk/SessionContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/SessionContracts.cs new file mode 100644 index 0000000..7d5c78d --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/SessionContracts.cs @@ -0,0 +1,21 @@ +namespace LanMountainDesktop.AirAppIsolation.Contracts; + +public sealed record AirAppSessionHandshakeRequest( + string AirAppId, + string SessionId, + string RuntimeMode, + string ProtocolVersion, + IReadOnlyList? RequestedCapabilities = null, + IReadOnlyDictionary? Metadata = null); + +public sealed record AirAppSessionHandshakeResponse( + bool Accepted, + string ProtocolVersion, + IReadOnlyList? GrantedCapabilities = null, + string? ErrorCode = null, + string? ErrorMessage = null); + +public sealed record AirAppReadyNotification( + string AirAppId, + string SessionId, + IReadOnlyList? UiSurfaces = null); diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsChangedEvent.cs b/airapp/LanMountainDesktop.AirAppSdk/SettingsChangedEvent.cs similarity index 87% rename from airapp/LanMountainDesktop.PluginSdk/SettingsChangedEvent.cs rename to airapp/LanMountainDesktop.AirAppSdk/SettingsChangedEvent.cs index e86a596..82bc7bc 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsChangedEvent.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/SettingsChangedEvent.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; -namespace LanMountainDesktop.PluginSdk; +namespace LanMountainDesktop.AirAppSdk; public sealed class SettingsChangedEvent { public SettingsChangedEvent( - SettingsScope scope, + AirAppSettingsScope scope, string? subjectId = null, string? placementId = null, string? sectionId = null, @@ -20,7 +20,7 @@ public sealed class SettingsChangedEvent : []; } - public SettingsScope Scope { get; } + public AirAppSettingsScope Scope { get; } public string? SubjectId { get; } diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/SettingsContracts.cs similarity index 64% rename from airapp/LanMountainDesktop.PluginSdk/SettingsContracts.cs rename to airapp/LanMountainDesktop.AirAppSdk/SettingsContracts.cs index e8d420b..73d3334 100644 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsContracts.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/SettingsContracts.cs @@ -1,31 +1,31 @@ using System.Text.Json; -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public sealed record PluginSettingsSnapshotRequest( +public sealed record AirAppSettingsSnapshotRequest( string Scope, string? SectionId = null, string? ComponentInstanceId = null); -public sealed record PluginSettingsSnapshotResponse( +public sealed record AirAppSettingsSnapshotResponse( string Scope, JsonElement Snapshot, string? ETag = null); -public sealed record PluginSettingsWriteRequest( +public sealed record AirAppSettingsWriteRequest( string Scope, JsonElement Value, string? SectionId = null, string? ComponentInstanceId = null, string? ETag = null); -public sealed record PluginSettingsWriteResponse( +public sealed record AirAppSettingsWriteResponse( bool Accepted, string? ETag = null, string? ErrorCode = null, string? ErrorMessage = null); -public sealed record PluginSettingsChangedNotification( +public sealed record AirAppSettingsChangedNotification( string Scope, JsonElement Value, string? SectionId = null, diff --git a/airapp/LanMountainDesktop.PluginSdk/UiContracts.cs b/airapp/LanMountainDesktop.AirAppSdk/UiContracts.cs similarity index 70% rename from airapp/LanMountainDesktop.PluginSdk/UiContracts.cs rename to airapp/LanMountainDesktop.AirAppSdk/UiContracts.cs index 40f4b5c..dbfbd11 100644 --- a/airapp/LanMountainDesktop.PluginSdk/UiContracts.cs +++ b/airapp/LanMountainDesktop.AirAppSdk/UiContracts.cs @@ -1,14 +1,14 @@ using System.Text.Json; -namespace LanMountainDesktop.PluginIsolation.Contracts; +namespace LanMountainDesktop.AirAppIsolation.Contracts; -public sealed record PluginUiSurfaceDescriptor( +public sealed record AirAppUiSurfaceDescriptor( string SurfaceId, string SurfaceKind, string Title, string? ComponentId = null); -public static class PluginUiSurfaceKinds +public static class AirAppUiSurfaceKinds { public const string DesktopComponent = "desktop-component"; public const string ComponentEditor = "component-editor"; @@ -16,36 +16,36 @@ public static class PluginUiSurfaceKinds public const string Window = "window"; } -public sealed record PluginUiAttachRequest( +public sealed record AirAppUiAttachRequest( string SurfaceId, string SurfaceKind, string? InstanceId = null, JsonElement? InitialState = null); -public sealed record PluginUiAttachResponse( +public sealed record AirAppUiAttachResponse( bool Accepted, JsonElement? InitialState = null, string? ErrorCode = null, string? ErrorMessage = null); -public sealed record PluginUiDetachNotification( +public sealed record AirAppUiDetachNotification( string SurfaceId, string SurfaceKind, string? InstanceId = null); -public sealed record PluginUiCommandRequest( +public sealed record AirAppUiCommandRequest( string SurfaceId, string CommandName, string? InstanceId = null, JsonElement? Payload = null); -public sealed record PluginUiCommandResponse( +public sealed record AirAppUiCommandResponse( bool Accepted, JsonElement? Payload = null, string? ErrorCode = null, string? ErrorMessage = null); -public sealed record PluginUiStateChangedNotification( +public sealed record AirAppUiStateChangedNotification( string SurfaceId, string SurfaceKind, string? InstanceId = null, diff --git a/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.props b/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.props new file mode 100644 index 0000000..b4f3bbf --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.props @@ -0,0 +1,14 @@ + + + airapp.json + .laapp + $(MSBuildProjectDirectory)\ + + true + false + + + + + + diff --git a/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.targets b/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.targets new file mode 100644 index 0000000..d61d2e6 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppSdk/buildTransitive/LanMountainDesktop.AirAppSdk.targets @@ -0,0 +1,51 @@ + + + + + + + + <_LanMountainAirAppBuildOutputDirectory>$(LanMountainAirAppBuildOutputDirectory) + <_LanMountainAirAppBuildOutputDirectory Condition="'$(_LanMountainAirAppBuildOutputDirectory)' == ''">$(TargetDir) + <_LanMountainAirAppBuildOutputDirectory Condition="'$(_LanMountainAirAppBuildOutputDirectory)' == ''">$(MSBuildProjectDirectory)\$(OutputPath) + <_LanMountainAirAppAssemblyName>$(LanMountainAirAppAssemblyName) + <_LanMountainAirAppAssemblyName Condition="'$(_LanMountainAirAppAssemblyName)' == '' and '$(AssemblyName)' != ''">$(AssemblyName) + <_LanMountainAirAppAssemblyName Condition="'$(_LanMountainAirAppAssemblyName)' == ''">$(MSBuildProjectName) + <_LanMountainAirAppPackageVersion>$(LanMountainAirAppPackageVersion) + <_LanMountainAirAppPackageVersion Condition="'$(_LanMountainAirAppPackageVersion)' == '' and '$(Version)' != ''">$(Version) + <_LanMountainAirAppPackageVersion Condition="'$(_LanMountainAirAppPackageVersion)' == ''">1.0.0 + <_LanMountainAirAppPackageOutputDirectory>$(LanMountainAirAppPackageOutputDirectory) + <_LanMountainAirAppPackageOutputDirectory Condition="'$(_LanMountainAirAppPackageOutputDirectory)' == ''">$(MSBuildProjectDirectory)\ + <_LanMountainAirAppPackageFileName>$(LanMountainAirAppPackageFileName) + <_LanMountainAirAppPackageFileName Condition="'$(_LanMountainAirAppPackageFileName)' == ''">$(_LanMountainAirAppAssemblyName).$(_LanMountainAirAppPackageVersion)$(LanMountainAirAppPackageExtension) + <_LanMountainAirAppPackagePath>$(LanMountainAirAppPackagePath) + <_LanMountainAirAppPackagePath Condition="'$(_LanMountainAirAppPackagePath)' == ''">$(_LanMountainAirAppPackageOutputDirectory)$(_LanMountainAirAppPackageFileName) + <_LanMountainAirAppManifestOutputPath>$(_LanMountainAirAppBuildOutputDirectory)$(LanMountainAirAppManifestFileName) + <_LanMountainAirAppDepsPath>$(ProjectDepsFilePath) + + + + + + + + + + + + + + diff --git a/airapp/LanMountainDesktop.PluginTemplate/LanMountainDesktop.PluginTemplate.csproj b/airapp/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj similarity index 83% rename from airapp/LanMountainDesktop.PluginTemplate/LanMountainDesktop.PluginTemplate.csproj rename to airapp/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj index 328de1b..5311217 100644 --- a/airapp/LanMountainDesktop.PluginTemplate/LanMountainDesktop.PluginTemplate.csproj +++ b/airapp/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj @@ -3,11 +3,11 @@ net10.0 $(NoWarn);NU5128 false - LanMountainDesktop.PluginTemplate + LanMountainDesktop.AirAppTemplate 1.0.0 LanMountainDesktop - Official dotnet new template package for LanMountainDesktop plugins. - LanMountainDesktop;Plugin;Template;dotnet-new + Official dotnet new template package for LanMountainDesktop AirApps (lightweight applications). + LanMountainDesktop;AirApp;Template;dotnet-new Template README.md https://github.com/wwiinnddyy/LanMountainDesktop diff --git a/airapp/LanMountainDesktop.PluginTemplate/README.md b/airapp/LanMountainDesktop.AirAppTemplate/README.md similarity index 100% rename from airapp/LanMountainDesktop.PluginTemplate/README.md rename to airapp/LanMountainDesktop.AirAppTemplate/README.md diff --git a/airapp/LanMountainDesktop.AirAppTemplate/content/.template.config/template.json b/airapp/LanMountainDesktop.AirAppTemplate/content/.template.config/template.json new file mode 100644 index 0000000..f1807df --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/.template.config/template.json @@ -0,0 +1,90 @@ +{ + "$schema": "http://json.schemastore.org/template", + "author": "LanMountainDesktop", + "classifications": [ + "LanMountainDesktop", + "AirApp", + "Desktop" + ], + "name": "LanMountainDesktop AirApp", + "identity": "LanMountainDesktop.AirAppTemplate.CSharp", + "shortName": "lmd-airapp", + "sourceName": "LanMountainDesktop.AirAppTemplate", + "preferNameDirectory": true, + "tags": { + "type": "project", + "language": "C#" + }, + "symbols": { + "airAppId": { + "type": "parameter", + "datatype": "text", + "defaultValue": "LanMountainDesktop.AirAppTemplate", + "description": "AirApp manifest id.", + "replaces": "__AIRAPP_ID__" + }, + "airAppAuthor": { + "type": "parameter", + "datatype": "text", + "defaultValue": "Your Name", + "description": "AirApp author.", + "replaces": "__AIRAPP_AUTHOR__" + }, + "airAppName": { + "type": "parameter", + "datatype": "text", + "defaultValue": "My AirApp", + "description": "Display name shown in the AirApp manifest.", + "replaces": "__AIRAPP_NAME__" + }, + "airAppDescription": { + "type": "parameter", + "datatype": "text", + "defaultValue": "AirApp generated from the official LanMountainDesktop template.", + "description": "AirApp description shown in the AirApp manifest.", + "replaces": "__AIRAPP_DESCRIPTION__" + }, + "airAppSdkVersion": { + "type": "parameter", + "datatype": "text", + "defaultValue": "1.0.0", + "description": "LanMountainDesktop.AirAppSdk package version.", + "replaces": "__AIRAPP_SDK_VERSION__" + }, + "componentId": { + "type": "parameter", + "datatype": "text", + "defaultValue": "my-component", + "description": "Desktop component identifier.", + "replaces": "__COMPONENT_ID__" + }, + "componentName": { + "type": "parameter", + "datatype": "text", + "defaultValue": "My Component", + "description": "Desktop component display name.", + "replaces": "__COMPONENT_NAME__" + }, + "componentDescription": { + "type": "parameter", + "datatype": "text", + "defaultValue": "A desktop component.", + "description": "Desktop component description.", + "replaces": "__COMPONENT_DESCRIPTION__" + }, + "windowId": { + "type": "parameter", + "datatype": "text", + "defaultValue": "my-window", + "description": "Window AirApp identifier.", + "replaces": "__WINDOW_ID__" + }, + "windowName": { + "type": "parameter", + "datatype": "text", + "defaultValue": "My Window", + "description": "Window AirApp display name.", + "replaces": "__WINDOW_NAME__" + } + } +} diff --git a/airapp/LanMountainDesktop.AirAppTemplate/content/AirApp.cs b/airapp/LanMountainDesktop.AirAppTemplate/content/AirApp.cs new file mode 100644 index 0000000..ddc1e34 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/AirApp.cs @@ -0,0 +1,44 @@ +using LanMountainDesktop.AirAppSdk; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace LanMountainDesktop.AirAppTemplate; + +/// +/// AirApp 入口。标记 并继承 。 +/// +[AirAppEntrance] +public sealed class AirApp : AirAppBase +{ + public override void Initialize(HostBuilderContext context, IServiceCollection services) + { + _ = context; + + // ── 桌面组件 ────────────────────────────────────────────────────── + // 组件在主进程内渲染,可放置到桌面网格。控件类型必须是 Avalonia Control。 + services.AddAirAppComponent( + new AirAppComponentOptions + { + ComponentId = "__COMPONENT_ID__", + DisplayName = "__COMPONENT_NAME__", + Description = "__COMPONENT_DESCRIPTION__", + Category = "Custom", + IconKey = "AppGeneric", + MinWidthCells = 2, + MinHeightCells = 2, + AllowDesktopPlacement = true + }); + + // ── 窗口轻应用 ──────────────────────────────────────────────────── + // 窗口内容由 AirAppHost 独立进程承载(跨进程隔离)。 + // 组件内通过 AirAppComponentContext.OpenWindowAsync("__WINDOW_ID__") 打开。 + services.AddAirAppWindow("__WINDOW_ID__", "__WINDOW_NAME__"); + + // ── 声明式设置页(宿主自动生成)─────────────────────────────────── + // services.AddAirAppSettingsSection( + // "my-settings", + // "My Settings", + // section => section.AddToggle("enable_feature", "Enable Feature", defaultValue: true), + // iconKey: "Settings"); + } +} diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/LanMountainDesktop.PluginTemplate.csproj b/airapp/LanMountainDesktop.AirAppTemplate/content/LanMountainDesktop.AirAppTemplate.csproj similarity index 62% rename from airapp/LanMountainDesktop.PluginTemplate/content/LanMountainDesktop.PluginTemplate.csproj rename to airapp/LanMountainDesktop.AirAppTemplate/content/LanMountainDesktop.AirAppTemplate.csproj index b763a85..9e13a7a 100644 --- a/airapp/LanMountainDesktop.PluginTemplate/content/LanMountainDesktop.PluginTemplate.csproj +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/LanMountainDesktop.AirAppTemplate.csproj @@ -5,15 +5,15 @@ enable 1.0.0 true - $(Version) + $(Version) - + - + diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/Localization/en-US.json b/airapp/LanMountainDesktop.AirAppTemplate/content/Localization/en-US.json similarity index 100% rename from airapp/LanMountainDesktop.PluginTemplate/content/Localization/en-US.json rename to airapp/LanMountainDesktop.AirAppTemplate/content/Localization/en-US.json diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/Localization/zh-CN.json b/airapp/LanMountainDesktop.AirAppTemplate/content/Localization/zh-CN.json similarity index 100% rename from airapp/LanMountainDesktop.PluginTemplate/content/Localization/zh-CN.json rename to airapp/LanMountainDesktop.AirAppTemplate/content/Localization/zh-CN.json diff --git a/airapp/LanMountainDesktop.AirAppTemplate/content/MyComponent.cs b/airapp/LanMountainDesktop.AirAppTemplate/content/MyComponent.cs new file mode 100644 index 0000000..b11a12a --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/MyComponent.cs @@ -0,0 +1,35 @@ +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using LanMountainDesktop.AirAppSdk; + +namespace LanMountainDesktop.AirAppTemplate; + +/// +/// 桌面组件控件。主进程内渲染,构造函数可接收 。 +/// +public sealed class MyComponent : UserControl +{ + private readonly TextBlock _text = new() + { + FontSize = 18, + FontWeight = FontWeight.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }; + + public MyComponent(AirAppComponentContext context) + { + _text.Text = $"Hello AirApp: {context.ComponentId}"; + Content = new StackPanel + { + Spacing = 8, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Children = + { + _text + } + }; + } +} diff --git a/airapp/LanMountainDesktop.AirAppTemplate/content/MyWindow.cs b/airapp/LanMountainDesktop.AirAppTemplate/content/MyWindow.cs new file mode 100644 index 0000000..cf2ddd5 --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/MyWindow.cs @@ -0,0 +1,24 @@ +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Media; +using LanMountainDesktop.AirAppSdk; + +namespace LanMountainDesktop.AirAppTemplate; + +/// +/// 窗口轻应用。内容由 AirAppHost 独立进程承载,复用宿主 FAAppWindow 外壳。 +/// +public sealed class MyWindow : AirAppWindowBase +{ + public MyWindow() + { + Content = new TextBlock + { + Text = "My AirApp Window", + FontSize = 24, + FontWeight = FontWeight.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }; + } +} diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/README.md b/airapp/LanMountainDesktop.AirAppTemplate/content/README.md similarity index 100% rename from airapp/LanMountainDesktop.PluginTemplate/content/README.md rename to airapp/LanMountainDesktop.AirAppTemplate/content/README.md diff --git a/airapp/LanMountainDesktop.AirAppTemplate/content/airapp.json b/airapp/LanMountainDesktop.AirAppTemplate/content/airapp.json new file mode 100644 index 0000000..2c6c30e --- /dev/null +++ b/airapp/LanMountainDesktop.AirAppTemplate/content/airapp.json @@ -0,0 +1,27 @@ +{ + "id": "__AIRAPP_ID__", + "name": "__AIRAPP_NAME__", + "description": "__AIRAPP_DESCRIPTION__", + "author": "__AIRAPP_AUTHOR__", + "version": "1.0.0", + "apiVersion": "1.0.0", + "entranceAssembly": "LanMountainDesktop.AirAppTemplate.dll", + "sharedContracts": [], + "runtime": { + "mode": "in-process" + }, + "components": [ + { + "id": "__COMPONENT_ID__", + "name": "__COMPONENT_NAME__", + "defaultWidth": 2, + "defaultHeight": 2 + } + ], + "windows": [ + { + "id": "__WINDOW_ID__", + "name": "__WINDOW_NAME__" + } + ] +} diff --git a/airapp/LanMountainDesktop.PluginSdk/ComponentChromeContext.cs b/airapp/LanMountainDesktop.PluginSdk/ComponentChromeContext.cs deleted file mode 100644 index 7f38f1b..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/ComponentChromeContext.cs +++ /dev/null @@ -1,11 +0,0 @@ -using LanMountainDesktop.PluginSdk; -using LanMountainDesktop.Shared.Contracts; - -namespace LanMountainDesktop.Host.Abstractions; - -public sealed record ComponentChromeContext( - string ComponentId, - string? PlacementId, - double CellSize, - AppearanceCornerRadiusTokens CornerRadiusTokens, - SettingsScope Scope = SettingsScope.App); diff --git a/airapp/LanMountainDesktop.PluginSdk/IPlugin.cs b/airapp/LanMountainDesktop.PluginSdk/IPlugin.cs deleted file mode 100644 index 33173d7..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPlugin.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace LanMountainDesktop.PluginSdk; - -public interface IPlugin -{ - void Initialize(HostBuilderContext context, IServiceCollection services); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginContext.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginContext.cs deleted file mode 100644 index 9b4c980..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginContext.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -[Obsolete("Plugin API 3.0.0 uses IPluginRuntimeContext and IServiceCollection-based initialization.")] -public interface IPluginContext : IPluginRuntimeContext -{ -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginExportRegistry.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginExportRegistry.cs deleted file mode 100644 index 35744bc..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginExportRegistry.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginExportRegistry -{ - IReadOnlyList GetExports(); - - IReadOnlyList GetExports(Type contractType); - - PluginServiceExportDescriptor? GetExport(Type contractType, string providerPluginId); - - TContract? GetExport(string providerPluginId) - where TContract : class; -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginMessageBus.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginMessageBus.cs deleted file mode 100644 index 11f8fbd..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginMessageBus.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginMessageBus -{ - IDisposable Subscribe(Action handler); - - void Publish(TMessage message); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginPackageManager.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginPackageManager.cs deleted file mode 100644 index 987d6d1..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginPackageManager.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginPackageManager -{ - IReadOnlyList GetInstalledPlugins(); - - PluginPackageInstallResult InstallPackage(string packagePath); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcContributor.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcContributor.cs deleted file mode 100644 index 7e06304..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginPublicIpcContributor.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginPublicIpcContributor -{ - void ConfigurePublicIpc(IPluginPublicIpcBuilder builder); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginRuntimeContext.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginRuntimeContext.cs deleted file mode 100644 index c7345ca..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginRuntimeContext.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginRuntimeContext -{ - PluginManifest Manifest { get; } - - string PluginDirectory { get; } - - string DataDirectory { get; } - - IServiceProvider Services { get; } - - IReadOnlyDictionary Properties { get; } - - IPluginAppearanceContext Appearance { get; } - - T? GetService(); - - bool TryGetProperty(string key, out T? value); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/IPluginWorkerContext.cs b/airapp/LanMountainDesktop.PluginSdk/IPluginWorkerContext.cs deleted file mode 100644 index 3aa8697..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/IPluginWorkerContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using LanMountainDesktop.PluginIsolation.Contracts; - -namespace LanMountainDesktop.PluginSdk; - -public interface IPluginWorkerContext -{ - string PluginId { get; } - - PluginManifest Manifest { get; } - - PluginRuntimeMode RuntimeMode { get; } - - string SessionId { get; } - - string HostPipeName { get; } - - string ProtocolVersion { get; } - - string PluginDirectory { get; } - - string DataDirectory { get; } - - IReadOnlyList GrantedCapabilities { get; } - - IReadOnlyDictionary StartupProperties { get; } -} diff --git a/airapp/LanMountainDesktop.PluginSdk/ISettingsCatalog.cs b/airapp/LanMountainDesktop.PluginSdk/ISettingsCatalog.cs deleted file mode 100644 index 61efbd0..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/ISettingsCatalog.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace LanMountainDesktop.PluginSdk; - -public interface ISettingsCatalog -{ - IReadOnlyList GetSections(); - - IReadOnlyList GetSections(SettingsScope scope); -} diff --git a/airapp/LanMountainDesktop.PluginSdk/InstalledPluginInfo.cs b/airapp/LanMountainDesktop.PluginSdk/InstalledPluginInfo.cs deleted file mode 100644 index 804bcbb..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/InstalledPluginInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public sealed record InstalledPluginInfo( - PluginManifest Manifest, - bool IsEnabled, - bool IsLoaded, - bool IsPackage, - string? ErrorMessage); diff --git a/airapp/LanMountainDesktop.PluginSdk/LICENSE b/airapp/LanMountainDesktop.PluginSdk/LICENSE deleted file mode 100644 index 044e1bf..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version of - the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginBase.cs b/airapp/LanMountainDesktop.PluginSdk/PluginBase.cs deleted file mode 100644 index 22c173d..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginBase.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace LanMountainDesktop.PluginSdk; - -public abstract class PluginBase : IPlugin -{ - public virtual void Initialize(HostBuilderContext context, IServiceCollection services) - { - } -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusTokens.cs b/airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusTokens.cs deleted file mode 100644 index 8e71cf1..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginCornerRadiusTokens.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Avalonia; -using LanMountainDesktop.Shared.Contracts; - -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginCornerRadiusTokens( - double Micro, - double Xs, - double Sm, - double Md, - double Lg, - double Xl, - double Island, - double Component) -{ - public double Get(PluginCornerRadiusPreset preset) - { - return preset switch - { - PluginCornerRadiusPreset.Default => Component, - PluginCornerRadiusPreset.Micro => Micro, - PluginCornerRadiusPreset.Xs => Xs, - PluginCornerRadiusPreset.Sm => Sm, - PluginCornerRadiusPreset.Md => Md, - PluginCornerRadiusPreset.Lg => Lg, - PluginCornerRadiusPreset.Xl => Xl, - PluginCornerRadiusPreset.Island => Island, - PluginCornerRadiusPreset.Component => Component, - _ => Component - }; - } - - public CornerRadius ToCornerRadius(PluginCornerRadiusPreset preset) - { - return new CornerRadius(Get(preset)); - } - - public static PluginCornerRadiusTokens FromShared(AppearanceCornerRadiusTokens tokens) - { - ArgumentNullException.ThrowIfNull(tokens); - - return new PluginCornerRadiusTokens( - tokens.Micro.TopLeft, - tokens.Xs.TopLeft, - tokens.Sm.TopLeft, - tokens.Md.TopLeft, - tokens.Lg.TopLeft, - tokens.Xl.TopLeft, - tokens.Island.TopLeft, - tokens.Component.TopLeft); - } -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentResizeMode.cs b/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentResizeMode.cs deleted file mode 100644 index 54954dd..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginDesktopComponentResizeMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public enum PluginDesktopComponentResizeMode -{ - Proportional = 0, - Free = 1 -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginEntranceAttribute.cs b/airapp/LanMountainDesktop.PluginSdk/PluginEntranceAttribute.cs deleted file mode 100644 index a9015eb..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginEntranceAttribute.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -public sealed class PluginEntranceAttribute : Attribute -{ -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcClientOptions.cs b/airapp/LanMountainDesktop.PluginSdk/PluginIpcClientOptions.cs deleted file mode 100644 index 72bee57..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcClientOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Text.Json.Serialization; -using LanMountainDesktop.PluginIsolation.Contracts; - -namespace LanMountainDesktop.PluginIsolation.Ipc; - -public sealed record PluginIpcClientOptions -{ - public required string PipeName { get; init; } - - public string ProtocolVersion { get; init; } = PluginIsolationProtocolVersion.Current; - - public TimeSpan ConnectTimeout { get; init; } = PluginIpcConstants.DefaultConnectTimeout; - - public TimeSpan RequestTimeout { get; init; } = PluginIpcConstants.DefaultRequestTimeout; - - public JsonSerializerContext SerializerContext { get; init; } = PluginIsolationJsonContext.Default; -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutedNotifyIds.cs b/airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutedNotifyIds.cs deleted file mode 100644 index 8c4b77d..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcRoutedNotifyIds.cs +++ /dev/null @@ -1,17 +0,0 @@ -using LanMountainDesktop.PluginIsolation.Contracts; - -namespace LanMountainDesktop.PluginIsolation.Ipc; - -public static class PluginIpcRoutedNotifyIds -{ - public const string SessionReady = PluginIpcRoutes.Session.Ready; - public const string LifecycleStateChanged = PluginIpcRoutes.Lifecycle.StateChanged; - public const string SettingsChanged = PluginIpcRoutes.Settings.Changed; - public const string AppearanceChanged = PluginIpcRoutes.Appearance.Changed; - public const string UiDetach = PluginIpcRoutes.Ui.Detach; - public const string UiStateChanged = PluginIpcRoutes.Ui.StateChanged; - public const string HeartbeatPing = PluginIpcRoutes.Heartbeat.Ping; - public const string HeartbeatPong = PluginIpcRoutes.Heartbeat.Pong; - public const string LogWrite = PluginIpcRoutes.Log.Write; - public const string FaultReport = PluginIpcRoutes.Fault.Report; -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIpcServerOptions.cs b/airapp/LanMountainDesktop.PluginSdk/PluginIpcServerOptions.cs deleted file mode 100644 index 498c0cb..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIpcServerOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Text.Json.Serialization; -using LanMountainDesktop.PluginIsolation.Contracts; - -namespace LanMountainDesktop.PluginIsolation.Ipc; - -public sealed record PluginIpcServerOptions -{ - public required string PipeName { get; init; } - - public string ProtocolVersion { get; init; } = PluginIsolationProtocolVersion.Current; - - public TimeSpan HeartbeatInterval { get; init; } = PluginIpcConstants.DefaultHeartbeatInterval; - - public TimeSpan HeartbeatTimeout { get; init; } = PluginIpcConstants.DefaultHeartbeatTimeout; - - public JsonSerializerContext SerializerContext { get; init; } = PluginIsolationJsonContext.Default; -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIsolationJsonContext.cs b/airapp/LanMountainDesktop.PluginSdk/PluginIsolationJsonContext.cs deleted file mode 100644 index 3e8951d..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIsolationJsonContext.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Text.Json.Serialization; - -namespace LanMountainDesktop.PluginIsolation.Contracts; - -[JsonSourceGenerationOptions( - PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] -[JsonSerializable(typeof(PluginCapabilityDeclaration))] -[JsonSerializable(typeof(List))] -[JsonSerializable(typeof(PluginSessionHandshakeRequest))] -[JsonSerializable(typeof(PluginSessionHandshakeResponse))] -[JsonSerializable(typeof(PluginReadyNotification))] -[JsonSerializable(typeof(PluginInitializeRequest))] -[JsonSerializable(typeof(PluginInitializeResponse))] -[JsonSerializable(typeof(PluginStopRequest))] -[JsonSerializable(typeof(PluginRestartRequest))] -[JsonSerializable(typeof(PluginLifecycleStateChanged))] -[JsonSerializable(typeof(PluginSettingsSnapshotRequest))] -[JsonSerializable(typeof(PluginSettingsSnapshotResponse))] -[JsonSerializable(typeof(PluginSettingsWriteRequest))] -[JsonSerializable(typeof(PluginSettingsWriteResponse))] -[JsonSerializable(typeof(PluginSettingsChangedNotification))] -[JsonSerializable(typeof(PluginAppearanceSnapshotRequest))] -[JsonSerializable(typeof(PluginMaterialSurfaceSnapshot))] -[JsonSerializable(typeof(PluginAppearanceSnapshot))] -[JsonSerializable(typeof(PluginAppearanceChangedNotification))] -[JsonSerializable(typeof(PluginUiSurfaceDescriptor))] -[JsonSerializable(typeof(List))] -[JsonSerializable(typeof(PluginUiAttachRequest))] -[JsonSerializable(typeof(PluginUiAttachResponse))] -[JsonSerializable(typeof(PluginUiDetachNotification))] -[JsonSerializable(typeof(PluginUiCommandRequest))] -[JsonSerializable(typeof(PluginUiCommandResponse))] -[JsonSerializable(typeof(PluginUiStateChangedNotification))] -[JsonSerializable(typeof(PluginHeartbeatPing))] -[JsonSerializable(typeof(PluginHeartbeatPong))] -[JsonSerializable(typeof(PluginLogEntry))] -[JsonSerializable(typeof(PluginFaultReport))] -public partial class PluginIsolationJsonContext : JsonSerializerContext; diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginIsolationProtocolVersion.cs b/airapp/LanMountainDesktop.PluginSdk/PluginIsolationProtocolVersion.cs deleted file mode 100644 index 64452b1..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginIsolationProtocolVersion.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; - -public static class PluginIsolationProtocolVersion -{ - public const string Current = "1.0"; -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginManifest.cs b/airapp/LanMountainDesktop.PluginSdk/PluginManifest.cs deleted file mode 100644 index 332f49e..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginManifest.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System.Text.Json; - -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginManifest( - string Id, - string Name, - string EntranceAssembly, - string? Description = null, - string? Author = null, - string? Version = null, - string? ApiVersion = null, - IReadOnlyList? SharedContracts = null, - PluginRuntimeConfiguration? Runtime = null) -{ - private static readonly JsonSerializerOptions SerializerOptions = new() - { - PropertyNameCaseInsensitive = true, - ReadCommentHandling = JsonCommentHandling.Skip, - AllowTrailingCommas = true - }; - - public static PluginManifest Load(string manifestPath) - { - ArgumentException.ThrowIfNullOrWhiteSpace(manifestPath); - - using var stream = File.OpenRead(manifestPath); - return Load(stream, manifestPath); - } - - public static PluginManifest Load(Stream stream, string sourceName) - { - ArgumentNullException.ThrowIfNull(stream); - ArgumentException.ThrowIfNullOrWhiteSpace(sourceName); - - var manifest = JsonSerializer.Deserialize(stream, SerializerOptions); - if (manifest is null) - { - throw new InvalidOperationException($"Failed to deserialize plugin manifest '{sourceName}'."); - } - - return manifest.NormalizeAndValidate(sourceName); - } - - public string ResolveEntranceAssemblyPath(string manifestPath) - { - ArgumentException.ThrowIfNullOrWhiteSpace(manifestPath); - - if (Path.IsPathRooted(EntranceAssembly)) - { - return Path.GetFullPath(EntranceAssembly); - } - - var manifestDirectory = Path.GetDirectoryName(Path.GetFullPath(manifestPath)) - ?? throw new InvalidOperationException($"Failed to determine the directory of '{manifestPath}'."); - - return Path.GetFullPath(Path.Combine(manifestDirectory, EntranceAssembly)); - } - - public PluginRuntimeMode RuntimeMode => - PluginRuntimeModes.TryParse(Runtime?.Mode, out var mode) ? mode : PluginRuntimeMode.InProcess; - - private PluginManifest NormalizeAndValidate(string manifestPath) - { - var normalizedSharedContracts = NormalizeSharedContracts(manifestPath, SharedContracts); - var normalizedRuntime = (Runtime ?? new PluginRuntimeConfiguration()).NormalizeAndValidate(manifestPath); - var normalized = this with - { - Id = RequireValue(Id, nameof(Id), manifestPath), - Name = RequireValue(Name, nameof(Name), manifestPath), - EntranceAssembly = RequireValue(EntranceAssembly, nameof(EntranceAssembly), manifestPath), - Description = NormalizeOptionalValue(Description), - Author = NormalizeOptionalValue(Author), - Version = NormalizeOptionalValue(Version), - ApiVersion = NormalizeOptionalValue(ApiVersion) ?? PluginSdkInfo.ApiVersion, - SharedContracts = normalizedSharedContracts, - Runtime = normalizedRuntime - }; - - if (!System.Version.TryParse(normalized.ApiVersion, out var requestedVersion)) - { - throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' declares an invalid API version '{normalized.ApiVersion}'."); - } - - if (!System.Version.TryParse(PluginSdkInfo.ApiVersion, out var currentVersion)) - { - throw new InvalidOperationException($"Plugin SDK API version '{PluginSdkInfo.ApiVersion}' is invalid."); - } - - if (requestedVersion.Major != currentVersion.Major) - { - throw new InvalidOperationException( - $"Plugin '{normalized.Id}' targets API version '{normalized.ApiVersion}', " + - $"but the host provides '{PluginSdkInfo.ApiVersion}'. " + - $"This host only supports API {PluginSdkInfo.ApiVersion} plugins."); - } - - return normalized; - } - - private static IReadOnlyList NormalizeSharedContracts( - string manifestPath, - IReadOnlyList? sharedContracts) - { - if (sharedContracts is null || sharedContracts.Count == 0) - { - return Array.Empty(); - } - - var normalized = new List(sharedContracts.Count); - var seenIds = new HashSet(StringComparer.OrdinalIgnoreCase); - - foreach (var contract in sharedContracts) - { - if (contract is null) - { - throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' contains a null shared contract declaration."); - } - - var normalizedContract = contract.NormalizeAndValidate(manifestPath); - var contractKey = $"{normalizedContract.Id}@{normalizedContract.Version}"; - if (!seenIds.Add(contractKey)) - { - throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' declares duplicate shared contract '{contractKey}'."); - } - - normalized.Add(normalizedContract); - } - - return normalized; - } - - private static string RequireValue(string? value, string propertyName, string manifestPath) - { - var normalized = NormalizeOptionalValue(value); - if (string.IsNullOrWhiteSpace(normalized)) - { - throw new InvalidOperationException( - $"Plugin manifest '{manifestPath}' is missing required property '{propertyName}'."); - } - - return normalized; - } - - private static string? NormalizeOptionalValue(string? value) - { - return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); - } -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginPackageInstallResult.cs b/airapp/LanMountainDesktop.PluginSdk/PluginPackageInstallResult.cs deleted file mode 100644 index 0aee5bd..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginPackageInstallResult.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginPackageInstallResult( - PluginManifest Manifest, - bool ReplacedExisting, - bool RestartRequired); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceRegistration.cs b/airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceRegistration.cs deleted file mode 100644 index a20525a..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginPublicIpcServiceRegistration.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginPublicIpcServiceRegistration( - Type ContractType, - string? ObjectId, - string[] NotifyIds); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeConfiguration.cs b/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeConfiguration.cs deleted file mode 100644 index 4d406f6..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginRuntimeConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginRuntimeConfiguration(string Mode = PluginRuntimeModes.InProcess) -{ - public PluginRuntimeMode RuntimeMode => - PluginRuntimeModes.TryParse(Mode, out var mode) ? mode : PluginRuntimeMode.InProcess; - - internal PluginRuntimeConfiguration NormalizeAndValidate(string manifestPath) - { - return this with - { - Mode = PluginRuntimeModes.NormalizeManifestValue(Mode, manifestPath) - }; - } -} diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginServiceExportDescriptor.cs b/airapp/LanMountainDesktop.PluginSdk/PluginServiceExportDescriptor.cs deleted file mode 100644 index f5aea71..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginServiceExportDescriptor.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public sealed record PluginServiceExportDescriptor( - string ProviderPluginId, - Type ContractType, - object ServiceInstance); diff --git a/airapp/LanMountainDesktop.PluginSdk/PluginWorkerEntranceAttribute.cs b/airapp/LanMountainDesktop.PluginSdk/PluginWorkerEntranceAttribute.cs deleted file mode 100644 index 9c7972b..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/PluginWorkerEntranceAttribute.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -public sealed class PluginWorkerEntranceAttribute : Attribute -{ -} diff --git a/airapp/LanMountainDesktop.PluginSdk/README.md b/airapp/LanMountainDesktop.PluginSdk/README.md deleted file mode 100644 index 0b8db80..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# LanMountainDesktop.PluginSdk - -Official SDK package for LanMountainDesktop plugins. - -## Includes - -- `IPlugin`/`PluginBase` entry abstractions -- `IPluginWorker`/`PluginWorkerBase` worker-side entry abstractions for isolated background mode -- `PluginManifest` and shared contract declarations -- `runtime.mode` manifest support for `in-proc`, `isolated-background`, and `isolated-window` -- desktop component registration extensions -- plugin runtime context and host service abstractions -- build-transitive packaging targets for `.laapp` output - -## Quick Start - -```xml - - - -``` - -Create `plugin.json` in your plugin project root, then run `dotnet build` to produce both build output and a `.laapp` package. diff --git a/airapp/LanMountainDesktop.PluginSdk/SessionContracts.cs b/airapp/LanMountainDesktop.PluginSdk/SessionContracts.cs deleted file mode 100644 index 014a6d8..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/SessionContracts.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace LanMountainDesktop.PluginIsolation.Contracts; - -public sealed record PluginSessionHandshakeRequest( - string PluginId, - string SessionId, - string RuntimeMode, - string ProtocolVersion, - IReadOnlyList? RequestedCapabilities = null, - IReadOnlyDictionary? Metadata = null); - -public sealed record PluginSessionHandshakeResponse( - bool Accepted, - string ProtocolVersion, - IReadOnlyList? GrantedCapabilities = null, - string? ErrorCode = null, - string? ErrorMessage = null); - -public sealed record PluginReadyNotification( - string PluginId, - string SessionId, - IReadOnlyList? UiSurfaces = null); diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsPageCategory.cs b/airapp/LanMountainDesktop.PluginSdk/SettingsPageCategory.cs deleted file mode 100644 index 1f0d66c..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsPageCategory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public enum SettingsPageCategory -{ - General = 0, - Appearance = 10, - Components = 20, - Plugins = 30, - PluginCatalog = 35, - [Obsolete("Use PluginCatalog instead.")] - PluginMarket = 35, - About = 40, - Dev = 50 -} diff --git a/airapp/LanMountainDesktop.PluginSdk/SettingsScope.cs b/airapp/LanMountainDesktop.PluginSdk/SettingsScope.cs deleted file mode 100644 index fd103a5..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/SettingsScope.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace LanMountainDesktop.PluginSdk; - -public enum SettingsScope -{ - App = 0, - Launcher = 1, - Plugin = 2, - ComponentInstance = 3 -} diff --git a/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.props b/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.props deleted file mode 100644 index 753846f..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.props +++ /dev/null @@ -1,14 +0,0 @@ - - - plugin.json - .laapp - $(MSBuildProjectDirectory)\ - - true - false - - - - - - diff --git a/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.targets b/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.targets deleted file mode 100644 index 53b88b2..0000000 --- a/airapp/LanMountainDesktop.PluginSdk/buildTransitive/LanMountainDesktop.PluginSdk.targets +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - <_LanMountainPluginBuildOutputDirectory>$(LanMountainPluginBuildOutputDirectory) - <_LanMountainPluginBuildOutputDirectory Condition="'$(_LanMountainPluginBuildOutputDirectory)' == ''">$(TargetDir) - <_LanMountainPluginBuildOutputDirectory Condition="'$(_LanMountainPluginBuildOutputDirectory)' == ''">$(MSBuildProjectDirectory)\$(OutputPath) - <_LanMountainPluginAssemblyName>$(LanMountainPluginAssemblyName) - <_LanMountainPluginAssemblyName Condition="'$(_LanMountainPluginAssemblyName)' == '' and '$(AssemblyName)' != ''">$(AssemblyName) - <_LanMountainPluginAssemblyName Condition="'$(_LanMountainPluginAssemblyName)' == ''">$(MSBuildProjectName) - <_LanMountainPluginPackageVersion>$(LanMountainPluginPackageVersion) - <_LanMountainPluginPackageVersion Condition="'$(_LanMountainPluginPackageVersion)' == '' and '$(Version)' != ''">$(Version) - <_LanMountainPluginPackageVersion Condition="'$(_LanMountainPluginPackageVersion)' == ''">1.0.0 - <_LanMountainPluginPackageOutputDirectory>$(LanMountainPluginPackageOutputDirectory) - <_LanMountainPluginPackageOutputDirectory Condition="'$(_LanMountainPluginPackageOutputDirectory)' == ''">$(MSBuildProjectDirectory)\ - <_LanMountainPluginPackageFileName>$(LanMountainPluginPackageFileName) - <_LanMountainPluginPackageFileName Condition="'$(_LanMountainPluginPackageFileName)' == ''">$(_LanMountainPluginAssemblyName).$(_LanMountainPluginPackageVersion)$(LanMountainPluginPackageExtension) - <_LanMountainPluginPackagePath>$(LanMountainPluginPackagePath) - <_LanMountainPluginPackagePath Condition="'$(_LanMountainPluginPackagePath)' == ''">$(_LanMountainPluginPackageOutputDirectory)$(_LanMountainPluginPackageFileName) - <_LanMountainPluginManifestOutputPath>$(_LanMountainPluginBuildOutputDirectory)$(LanMountainPluginManifestFileName) - <_LanMountainPluginDepsPath>$(ProjectDepsFilePath) - - - - - - - - - - - - - - diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/.template.config/template.json b/airapp/LanMountainDesktop.PluginTemplate/content/.template.config/template.json deleted file mode 100644 index 2dd0cf4..0000000 --- a/airapp/LanMountainDesktop.PluginTemplate/content/.template.config/template.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/template", - "author": "LanMountainDesktop", - "classifications": [ - "LanMountainDesktop", - "Plugin", - "Desktop" - ], - "name": "LanMountainDesktop Plugin", - "identity": "LanMountainDesktop.PluginTemplate.CSharp", - "shortName": "lmd-plugin", - "sourceName": "LanMountainDesktop.PluginTemplate", - "preferNameDirectory": true, - "tags": { - "type": "project", - "language": "C#" - }, - "symbols": { - "pluginId": { - "type": "parameter", - "datatype": "text", - "defaultValue": "LanMountainDesktop.PluginTemplate", - "description": "Plugin manifest id.", - "replaces": "__PLUGIN_ID__" - }, - "pluginAuthor": { - "type": "parameter", - "datatype": "text", - "defaultValue": "Your Name", - "description": "Plugin author.", - "replaces": "__PLUGIN_AUTHOR__" - }, - "pluginName": { - "type": "parameter", - "datatype": "text", - "defaultValue": "LanMountain Plugin Template", - "description": "Display name shown in plugin manifest.", - "replaces": "__PLUGIN_NAME__" - }, - "pluginDescription": { - "type": "parameter", - "datatype": "text", - "defaultValue": "Plugin generated from the official LanMountainDesktop template.", - "description": "Plugin description shown in plugin manifest.", - "replaces": "__PLUGIN_DESCRIPTION__" - }, - "pluginSdkVersion": { - "type": "parameter", - "datatype": "text", - "defaultValue": "5.0.0", - "description": "LanMountainDesktop.PluginSdk package version.", - "replaces": "__PLUGIN_SDK_VERSION__" - } - } -} diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/Plugin.cs b/airapp/LanMountainDesktop.PluginTemplate/content/Plugin.cs deleted file mode 100644 index bd2037e..0000000 --- a/airapp/LanMountainDesktop.PluginTemplate/content/Plugin.cs +++ /dev/null @@ -1,47 +0,0 @@ -using LanMountainDesktop.PluginSdk; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace LanMountainDesktop.PluginTemplate; - -[PluginEntrance] -public sealed class Plugin : PluginBase -{ - public override void Initialize(HostBuilderContext context, IServiceCollection services) - { - _ = context; - - // ── Option 1: Declarative settings (simple key-value options) ────────── - // The host generates a settings page automatically from the declared options. - // Supported option types: Toggle, Text, Number, Select, Path, List. - // - // services.AddPluginSettingsSection( - // "my-plugin-settings", - // "My Plugin Settings", - // section => section - // .AddToggle("enable_feature", "Enable Feature", defaultValue: true) - // .AddNumber("refresh_interval", "Refresh Interval", defaultValue: 30, minimum: 5, maximum: 120), - // iconKey: "PuzzlePiece"); - - // ── Option 2: Custom AXAML view (full Fluent Avalonia controls) ──────── - // Provide a SettingsPageBase subclass to use any Fluent Avalonia control - // (SettingsExpander, ColorPicker, Slider, etc.) — just like built-in pages. - // - // services.AddPluginSettingsSection( - // "my-plugin-settings", - // "My Plugin Settings", - // iconKey: "PuzzlePiece"); - // - // Or mix both: declare options AND set a custom view on the builder: - // - // services.AddPluginSettingsSection( - // "my-plugin-settings", - // "My Plugin Settings", - // section => section - // .SetCustomView() - // .AddToggle("enable_feature", "Enable Feature"), - // iconKey: "PuzzlePiece"); - - _ = services; - } -} diff --git a/airapp/LanMountainDesktop.PluginTemplate/content/plugin.json b/airapp/LanMountainDesktop.PluginTemplate/content/plugin.json deleted file mode 100644 index 1ffed34..0000000 --- a/airapp/LanMountainDesktop.PluginTemplate/content/plugin.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "__PLUGIN_ID__", - "name": "__PLUGIN_NAME__", - "description": "__PLUGIN_DESCRIPTION__", - "author": "__PLUGIN_AUTHOR__", - "version": "1.0.0", - "apiVersion": "5.0.0", - "entranceAssembly": "LanMountainDesktop.PluginTemplate.dll", - "sharedContracts": [], - "runtime": { - "mode": "in-proc" - } -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs deleted file mode 100644 index 5522802..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppAppearanceSnapshot.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Avalonia.Media; - -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Snapshot of the current appearance settings. -/// -public sealed class AirAppAppearanceSnapshot -{ - /// - /// Gets whether dark mode is enabled. - /// - public bool IsDarkMode { get; init; } - - /// - /// Gets the primary accent color. - /// - public Color AccentColor { get; init; } - - /// - /// Gets the glass effect opacity (0.0 - 1.0). - /// - public double GlassOpacity { get; init; } - - /// - /// Gets the corner radius preset. - /// - public AirAppCornerRadiusPreset CornerRadiusPreset { get; init; } - - /// - /// Gets the background color. - /// - public Color BackgroundColor { get; init; } - - /// - /// Gets the foreground (text) color. - /// - public Color ForegroundColor { get; init; } - - /// - /// Gets the border color. - /// - public Color BorderColor { get; init; } - - /// - /// Gets additional custom properties. - /// - public IReadOnlyDictionary? CustomProperties { get; init; } -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs deleted file mode 100644 index 8fd3560..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentOptions.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Options for registering an AirApp desktop component. -/// -public sealed class AirAppComponentOptions -{ - /// - /// Gets or sets the unique component identifier. - /// - public required string Id { get; set; } - - /// - /// Gets or sets the display name. - /// - public required string Name { get; set; } - - /// - /// Gets or sets the widget implementation type. - /// Must implement IAirAppWidget. - /// - public required Type WidgetType { get; set; } - - /// - /// Gets or sets the optional description. - /// - public string? Description { get; set; } - - /// - /// Gets or sets the default width in grid cells. - /// Default is 2. - /// - public int DefaultWidth { get; set; } = 2; - - /// - /// Gets or sets the default height in grid cells. - /// Default is 2. - /// - public int DefaultHeight { get; set; } = 2; - - /// - /// Gets or sets the resize mode. - /// - public AirAppComponentResizeMode ResizeMode { get; set; } = AirAppComponentResizeMode.Both; - - /// - /// Gets or sets whether this component can be added multiple times. - /// Default is true. - /// - public bool AllowMultipleInstances { get; set; } = true; - - /// - /// Gets or sets the category for grouping in the component library. - /// - public string? Category { get; set; } - - /// - /// Gets or sets the icon identifier. - /// - public string? IconKey { get; set; } -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs deleted file mode 100644 index c8feec4..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppComponentResizeMode.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Resize mode for AirApp desktop components. -/// -public enum AirAppComponentResizeMode -{ - /// - /// Cannot be resized. - /// - None = 0, - - /// - /// Can be resized horizontally only. - /// - Horizontal = 1, - - /// - /// Can be resized vertically only. - /// - Vertical = 2, - - /// - /// Can be resized in both directions. - /// - Both = 3 -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs deleted file mode 100644 index 828ae49..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppCornerRadiusPreset.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Corner radius presets. -/// -public enum AirAppCornerRadiusPreset -{ - /// - /// No rounded corners. - /// - None = 0, - - /// - /// Small corner radius (4px). - /// - Small = 1, - - /// - /// Medium corner radius (8px). - /// - Medium = 2, - - /// - /// Large corner radius (12px). - /// - Large = 3, - - /// - /// Extra large corner radius (16px). - /// - ExtraLarge = 4 -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs deleted file mode 100644 index dfba50f..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppRuntimeMode.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Runtime mode for AirApps. -/// -public enum AirAppRuntimeMode -{ - /// - /// Run in the host process (best performance, shared memory). - /// - InProcess = 0, - - /// - /// Run in an isolated background process (safer, separate memory). - /// - IsolatedBackground = 1, - - /// - /// Run in an isolated window process (full isolation). - /// - IsolatedWindow = 2 -} - -/// -/// Helper for parsing runtime modes. -/// -public static class AirAppRuntimeModes -{ - public static bool TryParse(string? mode, out AirAppRuntimeMode result) - { - result = AirAppRuntimeMode.InProcess; - - if (string.IsNullOrWhiteSpace(mode)) - { - return false; - } - - var normalized = mode.Trim().ToLowerInvariant(); - return normalized switch - { - "in-process" => SetResult(AirAppRuntimeMode.InProcess, out result), - "isolated-background" => SetResult(AirAppRuntimeMode.IsolatedBackground, out result), - "isolated-window" => SetResult(AirAppRuntimeMode.IsolatedWindow, out result), - _ => false - }; - } - - private static bool SetResult(AirAppRuntimeMode mode, out AirAppRuntimeMode result) - { - result = mode; - return true; - } -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs deleted file mode 100644 index cbbacdb..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppSdkInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// AirApp SDK information. -/// -public static class AirAppSdkInfo -{ - /// - /// Current SDK version. - /// - public const string SdkVersion = "6.0.0"; - - /// - /// Current API version. - /// AirApps must target this major version to be compatible. - /// - public const string ApiVersion = "6.0.0"; - - /// - /// Gets the SDK display name. - /// - public static string DisplayName => "LanMountainDesktop AirApp SDK"; - - /// - /// Gets the default manifest file name. - /// - public const string ManifestFileName = "airapp.json"; - - /// - /// Gets the package file extension. - /// - public const string PackageExtension = ".laapp"; -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs b/airappsdk/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs deleted file mode 100644 index 827d7b9..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/AirAppServiceCollectionExtensions.cs +++ /dev/null @@ -1,158 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Extension methods for registering AirApp services. -/// -public static class AirAppServiceCollectionExtensions -{ - /// - /// Register a desktop component. - /// - public static IServiceCollection AddAirAppComponent( - this IServiceCollection services, - string id, - string name, - Action? configure = null) - where TWidget : class, IAirAppWidget - { - var options = new AirAppComponentOptions - { - Id = id, - Name = name, - WidgetType = typeof(TWidget) - }; - - configure?.Invoke(options); - - // Register the widget as transient (new instance per placement) - services.AddTransient(); - - // Register the component options (will be picked up by the host) - services.AddSingleton(options); - - return services; - } - - /// - /// Register a window. - /// - public static IServiceCollection AddAirAppWindow( - this IServiceCollection services, - string id, - string name) - where TWindow : class, IAirAppWindow - { - // Register the window as transient (new instance per open) - services.AddTransient(); - - // TODO: Register window metadata - return services; - } - - /// - /// Register a settings section (declarative). - /// - public static IServiceCollection AddAirAppSettings( - this IServiceCollection services, - string id, - string name, - Action? configure = null) - { - var builder = new AirAppSettingsSectionBuilder(id, name); - configure?.Invoke(builder); - - // Register the settings section - services.AddSingleton(builder.Build()); - - return services; - } -} - -/// -/// Builder for settings sections. -/// -public sealed class AirAppSettingsSectionBuilder -{ - private readonly string _id; - private readonly string _name; - private readonly List _options = new(); - - internal AirAppSettingsSectionBuilder(string id, string name) - { - _id = id; - _name = name; - } - - public AirAppSettingsSectionBuilder AddToggle(string key, string label, bool defaultValue = false) - { - _options.Add(new AirAppSettingOption - { - Key = key, - Label = label, - Type = "toggle", - DefaultValue = defaultValue - }); - return this; - } - - public AirAppSettingsSectionBuilder AddText(string key, string label, string? defaultValue = null) - { - _options.Add(new AirAppSettingOption - { - Key = key, - Label = label, - Type = "text", - DefaultValue = defaultValue - }); - return this; - } - - public AirAppSettingsSectionBuilder AddNumber(string key, string label, double defaultValue = 0, double? minimum = null, double? maximum = null) - { - _options.Add(new AirAppSettingOption - { - Key = key, - Label = label, - Type = "number", - DefaultValue = defaultValue, - Minimum = minimum, - Maximum = maximum - }); - return this; - } - - internal AirAppSettingsSection Build() - { - return new AirAppSettingsSection - { - Id = _id, - Name = _name, - Options = _options - }; - } -} - -/// -/// Settings section metadata. -/// -public sealed class AirAppSettingsSection -{ - public required string Id { get; init; } - public required string Name { get; init; } - public required List Options { get; init; } -} - -/// -/// Individual setting option. -/// -public sealed class AirAppSettingOption -{ - public required string Key { get; init; } - public required string Label { get; init; } - public required string Type { get; init; } - public object? DefaultValue { get; init; } - public double? Minimum { get; init; } - public double? Maximum { get; init; } -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs b/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs deleted file mode 100644 index e156a34..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/IAirAppAppearanceContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace LanMountainDesktop.AirAppSdk; - -/// -/// Provides appearance and theme context. -/// -public interface IAirAppAppearanceContext -{ - /// - /// Gets the current appearance snapshot. - /// - AirAppAppearanceSnapshot CurrentSnapshot { get; } - - /// - /// Subscribe to appearance changes. - /// - /// Change handler - /// Subscription token - IDisposable SubscribeToChanges(Action handler); -} diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj b/airappsdk/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj deleted file mode 100644 index aec2265..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/LanMountainDesktop.AirAppSdk.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - net10.0 - enable - enable - preview - true - - - LanMountainDesktop.AirAppSdk - 6.0.0 - LanMountainDesktop Team - Official SDK for developing AirApps (Lightweight Applications) for LanMountainDesktop - lanmountaindesktop;airapp;sdk;plugin;avalonia - MIT - https://github.com/LanMountain/LanMountainDesktop - - - true - - - - - - - - - - - - - - diff --git a/airappsdk/LanMountainDesktop.AirAppSdk/README.md b/airappsdk/LanMountainDesktop.AirAppSdk/README.md deleted file mode 100644 index 6763488..0000000 --- a/airappsdk/LanMountainDesktop.AirAppSdk/README.md +++ /dev/null @@ -1,363 +0,0 @@ -# LanMountainDesktop.AirAppSdk - -Official SDK for developing AirApps (Lightweight Applications) for LanMountainDesktop. - -## What is an AirApp? - -AirApp is the next-generation application framework for LanMountainDesktop. It provides a unified development experience for creating: - -- **Desktop Components** - Widgets that live on the desktop -- **Window Applications** - Standalone windowed apps -- **Background Services** - Services that run in the background -- **Hybrid Apps** - Apps that combine multiple modes - -## Quick Start - -### Installation - -```bash -# Install the SDK package -dotnet add package LanMountainDesktop.AirAppSdk -``` - -### Create Your First AirApp - -1. **Create a new project** - -```bash -dotnet new classlib -n MyFirstAirApp -cd MyFirstAirApp -dotnet add package LanMountainDesktop.AirAppSdk -``` - -2. **Create the entry point** - -```csharp -using LanMountainDesktop.AirAppSdk; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace MyFirstAirApp; - -[AirAppEntrance] -public class MyAirApp : AirAppBase -{ - public override void Initialize(HostBuilderContext context, IServiceCollection services) - { - // Register a desktop component - services.AddAirAppComponent("my-widget", "My Widget"); - } -} -``` - -3. **Create a widget** - -```csharp -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using LanMountainDesktop.AirAppSdk; - -namespace MyFirstAirApp; - -public class MyWidget : AirAppWidgetBase -{ - public MyWidget() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - // Simple widget with a TextBlock - Content = new TextBlock - { - Text = "Hello from AirApp!", - HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center - }; - } - - protected override void OnAttachedCore() - { - // Called when widget is added to desktop - Context.Logger.Info("My widget attached!"); - } -} -``` - -4. **Create manifest file** (`airapp.json`) - -```json -{ - "id": "com.example.myfirstairapp", - "name": "My First AirApp", - "version": "1.0.0", - "apiVersion": "6.0.0", - "author": "Your Name", - "description": "My first AirApp for LanMountainDesktop", - "entranceAssembly": "MyFirstAirApp.dll", - "runtime": { - "mode": "in-process" - } -} -``` - -5. **Build the project** - -```bash -dotnet build -c Release -``` - -This will produce a `.laapp` package in `bin/Release/net10.0/MyFirstAirApp.laapp`. - -## Core Concepts - -### AirAppBase - -The entry point for your AirApp. Override `Initialize()` to register components and services: - -```csharp -[AirAppEntrance] -public class MyAirApp : AirAppBase -{ - public override void Initialize(HostBuilderContext context, IServiceCollection services) - { - // Register components - services.AddAirAppComponent("widget-id", "Widget Name"); - - // Register windows - services.AddAirAppWindow("window-id", "Window Name"); - - // Register your services - services.AddSingleton(); - } - - public override async Task OnStartedAsync(IAirAppRuntimeContext context) - { - // Runtime initialization - context.Logger.Info("AirApp started!"); - } -} -``` - -### Desktop Components - -Create widgets that appear on the desktop: - -```csharp -public class ClockWidget : AirAppWidgetBase -{ - private TextBlock _timeText; - - public ClockWidget() - { - _timeText = new TextBlock(); - Content = _timeText; - - // Update every second - DispatcherTimer.Run(() => - { - _timeText.Text = DateTime.Now.ToString("HH:mm:ss"); - return true; - }, TimeSpan.FromSeconds(1)); - } - - protected override void OnAppearanceChangedCore(AirAppAppearanceSnapshot snapshot) - { - // Respond to theme changes - _timeText.Foreground = new SolidColorBrush(snapshot.ForegroundColor); - } -} -``` - -### Windows - -Create standalone windows: - -```csharp -public class MyWindow : AirAppWindowBase -{ - public override AirAppWindowDescriptor Descriptor => new() - { - Title = "My Window", - Width = 800, - Height = 600, - ChromeMode = AirAppWindowChromeMode.Standard, - CanResize = true - }; - - public MyWindow() - { - Content = new TextBlock { Text = "Hello from window!" }; - } - - public override async Task OnWindowOpeningAsync() - { - // Async initialization before window opens - await LoadDataAsync(); - } -} -``` - -### Runtime Context - -Access runtime services: - -```csharp -protected override async Task OnStartedAsync(IAirAppRuntimeContext context) -{ - // Get data directories - var dataDir = context.DataDirectory; - var cacheDir = context.CacheDirectory; - - // Use services - var myService = context.Services.GetService(); - - // Log messages - context.Logger.Info("AirApp started!"); - - // Open a window - await context.OpenWindowAsync("my-window"); - - // Subscribe to messages - context.MessageBus.Subscribe("theme-changed", payload => - { - context.Logger.Info("Theme changed!"); - }); -} -``` - -## API Reference - -### Core Interfaces - -- `IAirApp` - AirApp entry point -- `IAirAppWidget` - Desktop component widget -- `IAirAppWindow` - Window application -- `IAirAppRuntimeContext` - Runtime services and context -- `IAirAppComponentContext` - Component instance context - -### Base Classes - -- `AirAppBase` - Base implementation of IAirApp -- `AirAppWidgetBase` - Base class for widgets -- `AirAppWindowBase` - Base class for windows - -### Configuration - -- `AirAppManifest` - Manifest file structure -- `AirAppComponentOptions` - Component registration options -- `AirAppWindowDescriptor` - Window configuration -- `AirAppRuntimeMode` - Runtime isolation modes - -### Services - -- `IAirAppLogger` - Logging service -- `IAirAppMessageBus` - Inter-app messaging -- `IAirAppAppearanceContext` - Theme and appearance - -## Runtime Modes - -### In-Process (Default) - -Best performance, runs in the host process: - -```json -{ - "runtime": { - "mode": "in-process" - } -} -``` - -### Isolated Background - -Runs in a separate background process: - -```json -{ - "runtime": { - "mode": "isolated-background" - } -} -``` - -### Isolated Window - -Runs in a completely isolated window process: - -```json -{ - "runtime": { - "mode": "isolated-window" - } -} -``` - -## Packaging - -Your AirApp is automatically packaged as a `.laapp` file when you build: - -```bash -dotnet build -c Release -``` - -The package includes: -- All assemblies -- The `airapp.json` manifest -- Any additional resources - -## Migration from Plugin SDK v5 - -If you're migrating from the older Plugin SDK: - -1. Update package reference: - ```xml - - - - - - ``` - -2. Update manifest file: `plugin.json` → `airapp.json` - -3. Update namespaces: - ```csharp - // Old - using LanMountainDesktop.PluginSdk; - [PluginEntrance] - public class Plugin : PluginBase { } - - // New - using LanMountainDesktop.AirAppSdk; - [AirAppEntrance] - public class MyAirApp : AirAppBase { } - ``` - -4. Update API calls (mostly compatible, minor naming changes) - -## Examples - -See the `samples/` directory for complete examples: - -- **SimpleWidget** - Basic desktop component -- **ClockWidget** - Time display with auto-update -- **WindowApp** - Standalone window application -- **HybridApp** - Component + window combination - -## Documentation - -- [Full API Documentation](https://docs.lanmountain.com/airapp-sdk) -- [Development Guide](https://docs.lanmountain.com/airapp-dev-guide) -- [Best Practices](https://docs.lanmountain.com/airapp-best-practices) - -## Support - -- GitHub Issues: https://github.com/LanMountain/LanMountainDesktop/issues -- Discord: https://discord.gg/lanmountain -- Documentation: https://docs.lanmountain.com - -## License - -MIT License - See LICENSE file for details diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj b/airappsdk/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj deleted file mode 100644 index 9bd0e04..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/LanMountainDesktop.AirAppTemplate.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - Template - 6.0.0 - LanMountainDesktop.AirAppTemplate - LanMountainDesktop AirApp Templates - LanMountainDesktop Team - Project templates for creating AirApps for LanMountainDesktop - templates;lanmountaindesktop;airapp;dotnet-new - net10.0 - true - false - content - $(NoWarn);NU5128 - true - - - - - - - diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/.template.config/template.json b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/.template.config/template.json deleted file mode 100644 index 45f9e94..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/.template.config/template.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/template", - "author": "LanMountainDesktop Team", - "classifications": ["LanMountainDesktop", "AirApp", "Component"], - "identity": "LanMountainDesktop.AirApp.Component", - "name": "LanMountainDesktop AirApp - Desktop Component", - "shortName": "lmd-airapp-component", - "tags": { - "language": "C#", - "type": "project" - }, - "sourceName": "LanMountainDesktop.AirApp.ComponentTemplate", - "preferNameDirectory": true, - "symbols": { - "ComponentId": { - "type": "parameter", - "datatype": "string", - "defaultValue": "my-widget", - "replaces": "my-widget", - "description": "The unique identifier for the component" - }, - "ComponentName": { - "type": "parameter", - "datatype": "string", - "defaultValue": "My Widget", - "replaces": "My Widget", - "description": "The display name for the component" - }, - "AuthorName": { - "type": "parameter", - "datatype": "string", - "defaultValue": "Your Name", - "replaces": "Your Name", - "description": "The author name" - } - } -} diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/LanMountainDesktop.AirApp.ComponentTemplate.csproj b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/LanMountainDesktop.AirApp.ComponentTemplate.csproj deleted file mode 100644 index 18b968e..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/LanMountainDesktop.AirApp.ComponentTemplate.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - net10.0 - enable - enable - preview - - - - - - - - - - PreserveNewest - - - diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyAirApp.cs b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyAirApp.cs deleted file mode 100644 index 2af06dd..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyAirApp.cs +++ /dev/null @@ -1,40 +0,0 @@ -using LanMountainDesktop.AirAppSdk; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace LanMountainDesktop.AirApp.ComponentTemplate; - -/// -/// AirApp entry point. -/// -[AirAppEntrance] -public sealed class MyAirApp : AirAppBase -{ - public override void Initialize(HostBuilderContext context, IServiceCollection services) - { - // Register the desktop component - services.AddAirAppComponent( - "my-widget", - "My Widget", - options => - { - options.Description = "A sample desktop component"; - options.DefaultWidth = 2; - options.DefaultHeight = 2; - options.ResizeMode = AirAppComponentResizeMode.Both; - options.Category = "Custom"; - options.IconKey = "AppGeneric"; - }); - } - - public override Task OnStartedAsync(IAirAppRuntimeContext context) - { - context.Logger.Info("My AirApp started successfully!"); - return Task.CompletedTask; - } - - public override Task OnStoppingAsync() - { - return Task.CompletedTask; - } -} diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyWidget.cs b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyWidget.cs deleted file mode 100644 index 54e4ef5..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/MyWidget.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Layout; -using Avalonia.Media; -using Avalonia.Threading; -using LanMountainDesktop.AirAppSdk; - -namespace LanMountainDesktop.AirApp.ComponentTemplate; - -/// -/// Desktop component widget implementation. -/// -public sealed class MyWidget : AirAppWidgetBase -{ - private readonly TextBlock _titleText; - private readonly TextBlock _timeText; - private readonly DispatcherTimer _timer; - - public MyWidget() - { - // Create UI - _titleText = new TextBlock - { - Text = "My Widget", - FontSize = 16, - FontWeight = FontWeight.Bold, - HorizontalAlignment = HorizontalAlignment.Center - }; - - _timeText = new TextBlock - { - FontSize = 24, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }; - - var panel = new StackPanel - { - Spacing = 8, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }; - panel.Children.Add(_titleText); - panel.Children.Add(_timeText); - - Content = panel; - - // Setup timer to update time - _timer = new DispatcherTimer - { - Interval = TimeSpan.FromSeconds(1) - }; - _timer.Tick += (s, e) => UpdateTime(); - } - - protected override void OnAttachedCore() - { - Context.Logger.Info($"Widget attached: {Context.ComponentId} at {Context.PlacementId}"); - UpdateTime(); - _timer.Start(); - } - - protected override void OnDetachedCore() - { - Context.Logger.Info($"Widget detached: {Context.ComponentId}"); - _timer.Stop(); - } - - protected override void OnAppearanceChangedCore(AirAppAppearanceSnapshot snapshot) - { - // Respond to theme changes - _titleText.Foreground = new SolidColorBrush(snapshot.ForegroundColor); - _timeText.Foreground = new SolidColorBrush(snapshot.AccentColor); - - Context.Logger.Info($"Appearance changed: DarkMode={snapshot.IsDarkMode}"); - } - - private void UpdateTime() - { - _timeText.Text = DateTime.Now.ToString("HH:mm:ss"); - } -} diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/README.md b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/README.md deleted file mode 100644 index 5c3e9fa..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# LanMountainDesktop.AirApp.ComponentTemplate (Preview) - -> [!IMPORTANT] -> This template is an API prototype. The production LanMountainDesktop Host, AirAppRuntime, and AirAppHost do not discover `airapp.json` or load assemblies produced by this template. - -A prototype desktop-component AirApp project for exploring `LanMountainDesktop.AirAppSdk`. - -## Build - -```bash -dotnet build -c Release -``` - -This compiles the prototype project. The template project itself does not create a production-installable `.laapp` package. - -## Install - -There is currently no supported production install path for this output. Do not copy it to the plugins directory or submit it to the AirApp Market: production `.laapp` handling is the plugin package path and expects `plugin.json`, while this template uses `airapp.json`. - -## Development - -You can build the project to validate prototype API usage. An integrated preview/production loader is not implemented yet; `LanMountainDesktop.AirAppDevServer` also does not currently launch a real preview host. - -## Customize - -- Edit `MyWidget.cs` to modify the component UI and behavior -- Edit `airapp.json` to change metadata -- Add more components by creating additional widget classes and registering them in `MyAirApp.cs` diff --git a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/airapp.json b/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/airapp.json deleted file mode 100644 index b98f1aa..0000000 --- a/airappsdk/LanMountainDesktop.AirAppTemplate/templates/component/airapp.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "id": "com.example.LanMountainDesktop.AirApp.ComponentTemplate", - "name": "LanMountainDesktop.AirApp.ComponentTemplate", - "version": "1.0.0", - "apiVersion": "6.0.0", - "author": "Your Name", - "description": "A desktop component AirApp for LanMountainDesktop", - "entranceAssembly": "LanMountainDesktop.AirApp.ComponentTemplate.dll", - "runtime": { - "mode": "in-process", - "capabilities": ["desktop-component"] - }, - "components": [ - { - "id": "my-widget", - "name": "My Widget", - "defaultWidth": 2, - "defaultHeight": 2 - } - ] -} diff --git a/core/LanMountainDesktop.Core/Abstractions/Services/IAirAppLifecycleService.cs b/core/LanMountainDesktop.Core/Abstractions/Services/IAirAppLifecycleService.cs index cf192cd..8f3c0d2 100644 --- a/core/LanMountainDesktop.Core/Abstractions/Services/IAirAppLifecycleService.cs +++ b/core/LanMountainDesktop.Core/Abstractions/Services/IAirAppLifecycleService.cs @@ -23,7 +23,8 @@ public sealed record AirAppOpenRequest( string? SourceComponentId, string? SourcePlacementId, int RequesterProcessId, - string? TargetEntryId = null); + string? TargetEntryId = null, + string? AppPackagePath = null); public sealed record AirAppRegistrationRequest( string InstanceKey, diff --git a/core/LanMountainDesktop.Core/Launcher/LauncherIpc.cs b/core/LanMountainDesktop.Core/Launcher/LauncherIpc.cs index 503c971..b8dcef0 100644 --- a/core/LanMountainDesktop.Core/Launcher/LauncherIpc.cs +++ b/core/LanMountainDesktop.Core/Launcher/LauncherIpc.cs @@ -4,7 +4,7 @@ public enum StartupStage { Initializing, LoadingSettings, - LoadingPlugins, + LoadingAirApps, TrayReady, InitializingUI, ShellInitialized, diff --git a/core/LanMountainDesktop.Core/Launcher/LoadingState.cs b/core/LanMountainDesktop.Core/Launcher/LoadingState.cs index 595886e..889fe49 100644 --- a/core/LanMountainDesktop.Core/Launcher/LoadingState.cs +++ b/core/LanMountainDesktop.Core/Launcher/LoadingState.cs @@ -4,7 +4,7 @@ public enum LoadingItemType { System, Settings, - Plugin, + AirApp, Component, Resource, Data, diff --git a/core/LanMountainDesktop.Core/PendingPluginUpgradeStore.cs b/core/LanMountainDesktop.Core/PendingPluginUpgradeStore.cs index f39fb8e..2d226b5 100644 --- a/core/LanMountainDesktop.Core/PendingPluginUpgradeStore.cs +++ b/core/LanMountainDesktop.Core/PendingPluginUpgradeStore.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public enum PendingPluginOperation { diff --git a/core/LanMountainDesktop.Core/PluginPackageInstallOptions.cs b/core/LanMountainDesktop.Core/PluginPackageInstallOptions.cs index 4cf7b60..afec1dd 100644 --- a/core/LanMountainDesktop.Core/PluginPackageInstallOptions.cs +++ b/core/LanMountainDesktop.Core/PluginPackageInstallOptions.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public sealed class PluginPackageInstallOptions { diff --git a/core/LanMountainDesktop.Core/PluginPackageInstallResult.cs b/core/LanMountainDesktop.Core/PluginPackageInstallResult.cs index 9c923bf..69aa090 100644 --- a/core/LanMountainDesktop.Core/PluginPackageInstallResult.cs +++ b/core/LanMountainDesktop.Core/PluginPackageInstallResult.cs @@ -1,3 +1,3 @@ -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public sealed record PluginPackageInstallResult(string InstalledPackagePath, PluginPackageManifest Manifest); diff --git a/core/LanMountainDesktop.Core/PluginPackageInstaller.cs b/core/LanMountainDesktop.Core/PluginPackageInstaller.cs index f837ef9..7b30d71 100644 --- a/core/LanMountainDesktop.Core/PluginPackageInstaller.cs +++ b/core/LanMountainDesktop.Core/PluginPackageInstaller.cs @@ -1,4 +1,4 @@ -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public sealed class PluginPackageInstaller { diff --git a/core/LanMountainDesktop.Core/PluginPackageManifest.cs b/core/LanMountainDesktop.Core/PluginPackageManifest.cs index 77d102f..55bcfaf 100644 --- a/core/LanMountainDesktop.Core/PluginPackageManifest.cs +++ b/core/LanMountainDesktop.Core/PluginPackageManifest.cs @@ -1,3 +1,3 @@ -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public sealed record PluginPackageManifest(string Id, string Name, string Version); diff --git a/core/LanMountainDesktop.Core/PluginPackageManifestReader.cs b/core/LanMountainDesktop.Core/PluginPackageManifestReader.cs index 7fd0110..f74269d 100644 --- a/core/LanMountainDesktop.Core/PluginPackageManifestReader.cs +++ b/core/LanMountainDesktop.Core/PluginPackageManifestReader.cs @@ -1,7 +1,7 @@ using System.IO.Compression; using System.Text.Json; -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public static class PluginPackageManifestReader { diff --git a/core/LanMountainDesktop.Core/PluginPackagingConstants.cs b/core/LanMountainDesktop.Core/PluginPackagingConstants.cs index 8992cf9..099ba44 100644 --- a/core/LanMountainDesktop.Core/PluginPackagingConstants.cs +++ b/core/LanMountainDesktop.Core/PluginPackagingConstants.cs @@ -1,8 +1,8 @@ -namespace LanMountainDesktop.PluginPackaging; +namespace LanMountainDesktop.AirAppPackaging; public static class PluginPackagingConstants { - public const string ManifestFileName = "plugin.json"; + public const string ManifestFileName = "airapp.json"; public const string LegacyManifestFileName = "manifest.json"; public const string PackageFileExtension = ".laapp"; public const string LegacyPackageFileExtension = ".lmdp"; diff --git a/desktop/LanMountainDesktop.Launcher/Plugins/PluginInstallerService.cs b/desktop/LanMountainDesktop.Launcher/AirApps/AirAppInstallerService.cs similarity index 87% rename from desktop/LanMountainDesktop.Launcher/Plugins/PluginInstallerService.cs rename to desktop/LanMountainDesktop.Launcher/AirApps/AirAppInstallerService.cs index f09d8e1..8c48dc0 100644 --- a/desktop/LanMountainDesktop.Launcher/Plugins/PluginInstallerService.cs +++ b/desktop/LanMountainDesktop.Launcher/AirApps/AirAppInstallerService.cs @@ -2,14 +2,14 @@ using System.IO.Compression; using System.Text.Json; using LanMountainDesktop.Launcher.Models; -namespace LanMountainDesktop.Launcher.Plugins; +namespace LanMountainDesktop.Launcher.AirApps; /// -/// 插件安装服务 - 简化版,不依赖 PluginSdk +/// 插件安装服务 - 简化版,不依赖 AirAppSdk /// -internal sealed class PluginInstallerService +internal sealed class AirAppInstallerService { - private const string ManifestFileName = "plugin.json"; + private const string ManifestFileName = "airapp.json"; private const string LegacyManifestFileName = "manifest.json"; private const string PackageFileExtension = ".laapp"; private const string LegacyPackageFileExtension = ".lmdp"; @@ -25,25 +25,25 @@ internal sealed class PluginInstallerService public LauncherResult InstallPackage(string sourcePath, string pluginsDirectory, string? appRoot = null) { var fullSourcePath = Path.GetFullPath(sourcePath); - var fullPluginsDirectory = Path.GetFullPath(pluginsDirectory); + var fullAirAppsDirectory = Path.GetFullPath(pluginsDirectory); if (!File.Exists(fullSourcePath)) { - throw new FileNotFoundException($"Plugin package '{fullSourcePath}' was not found.", fullSourcePath); + throw new FileNotFoundException($"AirApp package '{fullSourcePath}' was not found.", fullSourcePath); } - if (TryBuildElevationRequiredResult(fullPluginsDirectory, appRoot) is { } elevationRequiredResult) + if (TryBuildElevationRequiredResult(fullAirAppsDirectory, appRoot) is { } elevationRequiredResult) { return elevationRequiredResult; } var manifest = ReadManifestFromPackage(fullSourcePath); - Directory.CreateDirectory(fullPluginsDirectory); - var destinationPath = Path.Combine(fullPluginsDirectory, BuildInstalledPackageFileName(manifest.Id)); + Directory.CreateDirectory(fullAirAppsDirectory); + var destinationPath = Path.Combine(fullAirAppsDirectory, BuildInstalledPackageFileName(manifest.Id)); var stagingPath = destinationPath + ".incoming"; DeleteFileWithRetry(stagingPath); CopyWithRetry(fullSourcePath, stagingPath, overwrite: true); - RemoveExistingPluginPackages(fullPluginsDirectory, manifest.Id, destinationPath, stagingPath); + RemoveExistingAirAppPackages(fullAirAppsDirectory, manifest.Id, destinationPath, stagingPath); MoveWithOverwriteRetry(stagingPath, destinationPath); return new LauncherResult @@ -51,7 +51,7 @@ internal sealed class PluginInstallerService Success = true, Stage = "plugin.install", Code = "ok", - Message = "Plugin installed.", + Message = "AirApp installed.", InstalledPackagePath = destinationPath, ManifestId = manifest.Id, ManifestName = manifest.Name @@ -89,23 +89,23 @@ internal sealed class PluginInstallerService allowedRoot = EnsureTrailingSeparator(Path.Combine(Path.GetFullPath(localAppData), "LanMountainDesktop")); } - var normalizedPluginsDirectory = EnsureTrailingSeparator(Path.GetFullPath(pluginsDirectory)); - if (normalizedPluginsDirectory.StartsWith(allowedRoot, StringComparison.OrdinalIgnoreCase)) + var normalizedAirAppsDirectory = EnsureTrailingSeparator(Path.GetFullPath(pluginsDirectory)); + if (normalizedAirAppsDirectory.StartsWith(allowedRoot, StringComparison.OrdinalIgnoreCase)) { return null; } Logger.Warn( - $"Plugin installation requires explicit elevation. Reason='plugin_requires_elevation'; " + - $"PluginsDirectory='{pluginsDirectory}'; AllowedRoot='{allowedRoot}'."); + $"AirApp installation requires explicit elevation. Reason='plugin_requires_elevation'; " + + $"AirAppsDirectory='{pluginsDirectory}'; AllowedRoot='{allowedRoot}'."); return new LauncherResult { Success = false, Stage = "plugin.install", Code = "plugin_elevation_required", - Message = "Plugin installation outside the current user's LanMountainDesktop data directory requires explicit elevation.", - ErrorMessage = "Plugin installation target is outside the current user's LanMountainDesktop data directory.", + Message = "AirApp installation outside the current user's LanMountainDesktop data directory requires explicit elevation.", + ErrorMessage = "AirApp installation target is outside the current user's LanMountainDesktop data directory.", Details = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["pluginsDirectory"] = pluginsDirectory, @@ -115,7 +115,7 @@ internal sealed class PluginInstallerService }; } - public PluginManifest ReadManifestFromPackage(string packagePath) + public AirAppManifest ReadManifestFromPackage(string packagePath) { using var archive = ZipFile.OpenRead(packagePath); var entries = FindManifestEntries(archive, ManifestFileName); @@ -127,19 +127,19 @@ internal sealed class PluginInstallerService if (entries.Length == 0) { throw new InvalidOperationException( - $"Plugin package '{packagePath}' does not contain '{ManifestFileName}' or '{LegacyManifestFileName}'."); + $"AirApp package '{packagePath}' does not contain '{ManifestFileName}' or '{LegacyManifestFileName}'."); } if (entries.Length > 1) { throw new InvalidOperationException( - $"Plugin package '{packagePath}' contains multiple '{ManifestFileName}' files."); + $"AirApp package '{packagePath}' contains multiple '{ManifestFileName}' files."); } using var stream = entries[0].Open(); using var reader = new StreamReader(stream); var json = reader.ReadToEnd(); - var manifest = JsonSerializer.Deserialize(json, AppJsonContext.Default.PluginManifest); + var manifest = JsonSerializer.Deserialize(json, AppJsonContext.Default.AirAppManifest); if (manifest == null) { throw new InvalidOperationException($"Failed to deserialize manifest from '{packagePath}'."); @@ -154,7 +154,7 @@ internal sealed class PluginInstallerService .ToArray(); } - private void RemoveExistingPluginPackages(string pluginsDirectory, string pluginId, string destinationPath, string stagingPath) + private void RemoveExistingAirAppPackages(string pluginsDirectory, string pluginId, string destinationPath, string stagingPath) { var runtimeRootDirectory = EnsureTrailingSeparator(Path.Combine(Path.GetFullPath(pluginsDirectory), RuntimeDirectoryName)); var pendingDeletionDir = Path.Combine(pluginsDirectory, ".pending-deletions"); @@ -292,7 +292,7 @@ internal sealed class PluginInstallerService /// /// 简化的插件清单模型 /// -internal class PluginManifest +internal class AirAppManifest { public string Id { get; set; } = ""; public string Name { get; set; } = ""; diff --git a/desktop/LanMountainDesktop.Launcher/Plugins/PluginUpgradeQueueService.cs b/desktop/LanMountainDesktop.Launcher/AirApps/AirAppUpgradeQueueService.cs similarity index 84% rename from desktop/LanMountainDesktop.Launcher/Plugins/PluginUpgradeQueueService.cs rename to desktop/LanMountainDesktop.Launcher/AirApps/AirAppUpgradeQueueService.cs index fd11de1..619933f 100644 --- a/desktop/LanMountainDesktop.Launcher/Plugins/PluginUpgradeQueueService.cs +++ b/desktop/LanMountainDesktop.Launcher/AirApps/AirAppUpgradeQueueService.cs @@ -1,15 +1,15 @@ using System.Text.Json; using LanMountainDesktop.Launcher.Models; -namespace LanMountainDesktop.Launcher.Plugins; +namespace LanMountainDesktop.Launcher.AirApps; -internal sealed class PluginUpgradeQueueService +internal sealed class AirAppUpgradeQueueService { private const string PendingUpgradesFileName = ".pending-plugin-upgrades.json"; - private readonly PluginInstallerService _installerService; + private readonly AirAppInstallerService _installerService; - public PluginUpgradeQueueService(PluginInstallerService installerService) + public AirAppUpgradeQueueService(AirAppInstallerService installerService) { _installerService = installerService; } @@ -37,7 +37,7 @@ internal sealed class PluginUpgradeQueueService { if (!item.IsValid()) { - failures.Add(item.PluginId); + failures.Add(item.AirAppId); continue; } @@ -48,13 +48,13 @@ internal sealed class PluginUpgradeQueueService } catch { - failures.Add(item.PluginId); + failures.Add(item.AirAppId); } } var remaining = pending .Except(succeeded) - .Where(item => failures.Contains(item.PluginId, StringComparer.OrdinalIgnoreCase)) + .Where(item => failures.Contains(item.AirAppId, StringComparer.OrdinalIgnoreCase)) .ToList(); if (remaining.Count == 0) @@ -79,14 +79,14 @@ internal sealed class PluginUpgradeQueueService } internal sealed record PendingUpgrade( - string PluginId, + string AirAppId, string SourcePackagePath, string TargetVersion, DateTimeOffset CreatedAt) { public bool IsValid() { - return !string.IsNullOrWhiteSpace(PluginId) && + return !string.IsNullOrWhiteSpace(AirAppId) && !string.IsNullOrWhiteSpace(SourcePackagePath) && !string.IsNullOrWhiteSpace(TargetVersion) && File.Exists(SourcePackagePath); diff --git a/desktop/LanMountainDesktop.Launcher/AppJsonContext.cs b/desktop/LanMountainDesktop.Launcher/AppJsonContext.cs index 11833df..84ca2cb 100644 --- a/desktop/LanMountainDesktop.Launcher/AppJsonContext.cs +++ b/desktop/LanMountainDesktop.Launcher/AppJsonContext.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using LanMountainDesktop.Launcher.Models; -using LanMountainDesktop.Launcher.Plugins; +using LanMountainDesktop.Launcher.AirApps; using LanMountainDesktop.Shared.Contracts.Launcher; using LanMountainDesktop.Shared.IPC.Abstractions.Services; @@ -22,7 +22,7 @@ namespace LanMountainDesktop.Launcher; [JsonSerializable(typeof(PublicTaskbarStatus))] [JsonSerializable(typeof(PublicShellActivationResult))] [JsonSerializable(typeof(LauncherResult))] -[JsonSerializable(typeof(PluginManifest))] +[JsonSerializable(typeof(AirAppManifest))] [JsonSerializable(typeof(List))] [JsonSerializable(typeof(OobeStateFile))] [JsonSerializable(typeof(DataLocationConfig))] diff --git a/desktop/LanMountainDesktop.Launcher/CommandContext.cs b/desktop/LanMountainDesktop.Launcher/CommandContext.cs index 612263f..e0744cb 100644 --- a/desktop/LanMountainDesktop.Launcher/CommandContext.cs +++ b/desktop/LanMountainDesktop.Launcher/CommandContext.cs @@ -26,7 +26,7 @@ internal sealed class CommandContext /// public IReadOnlyList RawArgs { get; } - public bool IsLegacyPluginInstall => + public bool IsLegacyAirAppInstall => Options.ContainsKey("source") && Options.ContainsKey("plugins-dir") && Options.ContainsKey("result"); @@ -108,7 +108,7 @@ internal sealed class CommandContext return "debug-preview"; } - if (IsLegacyPluginInstall || string.Equals(Command, "plugin", StringComparison.OrdinalIgnoreCase)) + if (IsLegacyAirAppInstall || string.Equals(Command, "plugin", StringComparison.OrdinalIgnoreCase)) { return "plugin-install"; } diff --git a/desktop/LanMountainDesktop.Launcher/GlobalUsings.cs b/desktop/LanMountainDesktop.Launcher/GlobalUsings.cs index 4e6a5e9..ed9819b 100644 --- a/desktop/LanMountainDesktop.Launcher/GlobalUsings.cs +++ b/desktop/LanMountainDesktop.Launcher/GlobalUsings.cs @@ -2,5 +2,5 @@ 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.AirApps; global using LanMountainDesktop.Launcher.Startup; diff --git a/desktop/LanMountainDesktop.Launcher/Infrastructure/Commands.cs b/desktop/LanMountainDesktop.Launcher/Infrastructure/Commands.cs index 3139693..d812e06 100644 --- a/desktop/LanMountainDesktop.Launcher/Infrastructure/Commands.cs +++ b/desktop/LanMountainDesktop.Launcher/Infrastructure/Commands.cs @@ -7,7 +7,7 @@ namespace LanMountainDesktop.Launcher.Infrastructure; internal static class Commands { - public static async Task RunLegacyPluginInstallAsync(CommandContext context, PluginInstallerService installer) + public static async Task RunLegacyAirAppInstallAsync(CommandContext context, AirAppInstallerService installer) { var resultPath = context.GetOption("result"); LauncherResult result; @@ -37,8 +37,8 @@ internal static class Commands { var appRoot = ResolveAppRoot(context); _ = new DeploymentLocator(appRoot); - var pluginInstaller = new PluginInstallerService(); - var pluginUpgrades = new PluginUpgradeQueueService(pluginInstaller); + var pluginInstaller = new AirAppInstallerService(); + var pluginUpgrades = new AirAppUpgradeQueueService(pluginInstaller); LauncherResult result; try @@ -63,13 +63,13 @@ internal static class Commands private static LauncherResult ExecuteCore( CommandContext context, - PluginInstallerService pluginInstaller, - PluginUpgradeQueueService pluginUpgrades) + AirAppInstallerService pluginInstaller, + AirAppUpgradeQueueService pluginUpgrades) { switch (context.Command.ToLowerInvariant()) { case "plugin": - return ExecutePluginCommand(context, pluginInstaller, pluginUpgrades); + return ExecuteAirAppCommand(context, pluginInstaller, pluginUpgrades); default: return new LauncherResult { @@ -81,10 +81,10 @@ internal static class Commands } } - private static LauncherResult ExecutePluginCommand( + private static LauncherResult ExecuteAirAppCommand( CommandContext context, - PluginInstallerService pluginInstaller, - PluginUpgradeQueueService pluginUpgrades) + AirAppInstallerService pluginInstaller, + AirAppUpgradeQueueService pluginUpgrades) { switch (context.SubCommand.ToLowerInvariant()) { diff --git a/desktop/LanMountainDesktop.Launcher/Program.cs b/desktop/LanMountainDesktop.Launcher/Program.cs index 60c56a0..65e70f5 100644 --- a/desktop/LanMountainDesktop.Launcher/Program.cs +++ b/desktop/LanMountainDesktop.Launcher/Program.cs @@ -25,10 +25,10 @@ public static class Program try { - if (commandContext.IsLegacyPluginInstall) + if (commandContext.IsLegacyAirAppInstall) { - var installer = new PluginInstallerService(); - return await Commands.RunLegacyPluginInstallAsync(commandContext, installer).ConfigureAwait(false); + var installer = new AirAppInstallerService(); + return await Commands.RunLegacyAirAppInstallAsync(commandContext, installer).ConfigureAwait(false); } if (!commandContext.IsGuiCommand) diff --git a/desktop/LanMountainDesktop.Launcher/Resources/Strings.cs b/desktop/LanMountainDesktop.Launcher/Resources/Strings.cs index fe3a52d..a9fa5dd 100644 --- a/desktop/LanMountainDesktop.Launcher/Resources/Strings.cs +++ b/desktop/LanMountainDesktop.Launcher/Resources/Strings.cs @@ -65,14 +65,14 @@ public static class Strings public static string Loading_ButtonDetails => ResourceManager.GetString(nameof(Loading_ButtonDetails), Culture)!; public static string Loading_ButtonCancel => ResourceManager.GetString(nameof(Loading_ButtonCancel), Culture)!; public static string Loading_StageReady => ResourceManager.GetString(nameof(Loading_StageReady), Culture)!; - public static string Loading_ItemPlugin => ResourceManager.GetString(nameof(Loading_ItemPlugin), Culture)!; + public static string Loading_ItemAirApp => ResourceManager.GetString(nameof(Loading_ItemAirApp), Culture)!; public static string Loading_ItemComponent => ResourceManager.GetString(nameof(Loading_ItemComponent), Culture)!; public static string Loading_ItemResource => ResourceManager.GetString(nameof(Loading_ItemResource), Culture)!; public static string Loading_ItemData => ResourceManager.GetString(nameof(Loading_ItemData), Culture)!; public static string Loading_ItemDownload => ResourceManager.GetString(nameof(Loading_ItemDownload), Culture)!; public static string Loading_ItemProcess => ResourceManager.GetString(nameof(Loading_ItemProcess), Culture)!; public static string Loading_ItemComplete => ResourceManager.GetString(nameof(Loading_ItemComplete), Culture)!; - public static string Loading_TypePlugin => ResourceManager.GetString(nameof(Loading_TypePlugin), Culture)!; + public static string Loading_TypeAirApp => ResourceManager.GetString(nameof(Loading_TypeAirApp), Culture)!; public static string Loading_TypeComponent => ResourceManager.GetString(nameof(Loading_TypeComponent), Culture)!; public static string Loading_TypeResource => ResourceManager.GetString(nameof(Loading_TypeResource), Culture)!; public static string Loading_TypeData => ResourceManager.GetString(nameof(Loading_TypeData), Culture)!; @@ -90,7 +90,7 @@ public static class Strings public static string Update_DebugTitle => ResourceManager.GetString(nameof(Update_DebugTitle), Culture)!; public static string Update_DebugMessage => ResourceManager.GetString(nameof(Update_DebugMessage), Culture)!; public static string Update_Verifying => ResourceManager.GetString(nameof(Update_Verifying), Culture)!; - public static string Update_ApplyingPlugins => ResourceManager.GetString(nameof(Update_ApplyingPlugins), Culture)!; + public static string Update_ApplyingAirApps => ResourceManager.GetString(nameof(Update_ApplyingAirApps), Culture)!; public static string Update_CleaningUp => ResourceManager.GetString(nameof(Update_CleaningUp), Culture)!; public static string DebugDebug_Title => ResourceManager.GetString(nameof(DebugDebug_Title), Culture)!; public static string DebugDebug_SettingsTitle => ResourceManager.GetString(nameof(DebugDebug_SettingsTitle), Culture)!; @@ -207,7 +207,7 @@ public static class Strings public static string Coordinator_RunningHostMessage => ResourceManager.GetString(nameof(Coordinator_RunningHostMessage), Culture)!; public static string Preview_SplashInitializing => ResourceManager.GetString(nameof(Preview_SplashInitializing), Culture)!; public static string Preview_SplashCheckingUpdates => ResourceManager.GetString(nameof(Preview_SplashCheckingUpdates), Culture)!; - public static string Preview_SplashCheckingPlugins => ResourceManager.GetString(nameof(Preview_SplashCheckingPlugins), Culture)!; + public static string Preview_SplashCheckingAirApps => ResourceManager.GetString(nameof(Preview_SplashCheckingAirApps), Culture)!; public static string Preview_SplashLaunchingHost => ResourceManager.GetString(nameof(Preview_SplashLaunchingHost), Culture)!; public static string Preview_SplashReady => ResourceManager.GetString(nameof(Preview_SplashReady), Culture)!; public static string Preview_ErrorMessage => ResourceManager.GetString(nameof(Preview_ErrorMessage), Culture)!; diff --git a/desktop/LanMountainDesktop.Launcher/Shell/EntryHandlers/PreviewEntryHandler.cs b/desktop/LanMountainDesktop.Launcher/Shell/EntryHandlers/PreviewEntryHandler.cs index e12db89..1095a47 100644 --- a/desktop/LanMountainDesktop.Launcher/Shell/EntryHandlers/PreviewEntryHandler.cs +++ b/desktop/LanMountainDesktop.Launcher/Shell/EntryHandlers/PreviewEntryHandler.cs @@ -70,7 +70,7 @@ internal static class PreviewEntryHandler var messages = new[] { Strings.Preview_SplashInitializing, - Strings.Preview_SplashCheckingPlugins, + Strings.Preview_SplashCheckingAirApps, Strings.Preview_SplashLaunchingHost, Strings.Preview_SplashReady }; diff --git a/desktop/LanMountainDesktop.Launcher/Shell/LaunchUiPresenter.cs b/desktop/LanMountainDesktop.Launcher/Shell/LaunchUiPresenter.cs index e6b96f8..c1760ab 100644 --- a/desktop/LanMountainDesktop.Launcher/Shell/LaunchUiPresenter.cs +++ b/desktop/LanMountainDesktop.Launcher/Shell/LaunchUiPresenter.cs @@ -206,7 +206,7 @@ internal static class LaunchUiPresenter { StartupStage.Initializing => "initializing", StartupStage.LoadingSettings => "settings", - StartupStage.LoadingPlugins => "plugins", + StartupStage.LoadingAirApps => "plugins", StartupStage.TrayReady => "shell", StartupStage.InitializingUI => "ui", StartupStage.ShellInitialized => "shell", diff --git a/desktop/LanMountainDesktop.Launcher/Views/DevDebugWindow.axaml.cs b/desktop/LanMountainDesktop.Launcher/Views/DevDebugWindow.axaml.cs index 44c2c1a..813f81a 100644 --- a/desktop/LanMountainDesktop.Launcher/Views/DevDebugWindow.axaml.cs +++ b/desktop/LanMountainDesktop.Launcher/Views/DevDebugWindow.axaml.cs @@ -138,7 +138,7 @@ public partial class DevDebugWindow : Window /// private async Task SimulateSplashProgress(SplashWindow splashWindow) { - var stages = new[] { Strings.Preview_SplashInitializing, Strings.Preview_SplashCheckingPlugins, Strings.Preview_SplashLaunchingHost }; + var stages = new[] { Strings.Preview_SplashInitializing, Strings.Preview_SplashCheckingAirApps, Strings.Preview_SplashLaunchingHost }; var reporter = (ISplashStageReporter)splashWindow; for (int i = 0; i < stages.Length; i++) diff --git a/desktop/LanMountainDesktop.Launcher/Views/LoadingDetailsWindow.axaml.cs b/desktop/LanMountainDesktop.Launcher/Views/LoadingDetailsWindow.axaml.cs index ed5ab06..93079ff 100644 --- a/desktop/LanMountainDesktop.Launcher/Views/LoadingDetailsWindow.axaml.cs +++ b/desktop/LanMountainDesktop.Launcher/Views/LoadingDetailsWindow.axaml.cs @@ -237,7 +237,7 @@ public partial class LoadingDetailsWindow : Window { StartupStage.Initializing => "正在初始化系统...", StartupStage.LoadingSettings => "正在加载设置...", - StartupStage.LoadingPlugins => "正在加载插件...", + StartupStage.LoadingAirApps => "正在加载插件...", StartupStage.InitializingUI => "正在初始化界面...", StartupStage.ShellInitialized => "桌面程序已初始化", StartupStage.DesktopVisible => "桌面已经可见", @@ -256,7 +256,7 @@ public partial class LoadingDetailsWindow : Window return item.Type switch { - LoadingItemType.Plugin => Strings.Loading_ItemPlugin, + LoadingItemType.AirApp => Strings.Loading_ItemAirApp, LoadingItemType.Component => Strings.Loading_ItemComponent, LoadingItemType.Resource => Strings.Loading_ItemResource, LoadingItemType.Data => Strings.Loading_ItemData, @@ -269,7 +269,7 @@ public partial class LoadingDetailsWindow : Window /// 获取项图�? /// private static string GetItemIcon(LoadingItemType type) => type switch { - LoadingItemType.Plugin => "\uE768", + LoadingItemType.AirApp => "\uE768", LoadingItemType.Component => "\uE7C4", LoadingItemType.Resource => "\uE7C5", LoadingItemType.Data => "\uE7C6", @@ -360,7 +360,7 @@ public class LoadingItemViewModel : INotifyPropertyChanged private static string GetTypeLabel(LoadingItemType type) => type switch { - LoadingItemType.Plugin => Strings.Loading_TypePlugin, + LoadingItemType.AirApp => Strings.Loading_TypeAirApp, LoadingItemType.Component => Strings.Loading_TypeComponent, LoadingItemType.Resource => Strings.Loading_TypeResource, LoadingItemType.Data => Strings.Loading_TypeData, @@ -372,7 +372,7 @@ public class LoadingItemViewModel : INotifyPropertyChanged private static IBrush GetTypeBackground(LoadingItemType type) => type switch { - LoadingItemType.Plugin => new SolidColorBrush(Color.Parse("#E3F2FD")), + LoadingItemType.AirApp => new SolidColorBrush(Color.Parse("#E3F2FD")), LoadingItemType.Component => new SolidColorBrush(Color.Parse("#F3E5F5")), LoadingItemType.Resource => new SolidColorBrush(Color.Parse("#E8F5E9")), LoadingItemType.Data => new SolidColorBrush(Color.Parse("#FFF3E0")), @@ -382,7 +382,7 @@ public class LoadingItemViewModel : INotifyPropertyChanged private static IBrush GetTypeForeground(LoadingItemType type) => type switch { - LoadingItemType.Plugin => new SolidColorBrush(Color.Parse("#1976D2")), + LoadingItemType.AirApp => new SolidColorBrush(Color.Parse("#1976D2")), LoadingItemType.Component => new SolidColorBrush(Color.Parse("#7B1FA2")), LoadingItemType.Resource => new SolidColorBrush(Color.Parse("#388E3C")), LoadingItemType.Data => new SolidColorBrush(Color.Parse("#F57C00")), diff --git a/desktop/LanMountainDesktop/plugins/PluginCatalogEntry.cs b/desktop/LanMountainDesktop/AirApps/AirAppCatalogEntry.cs similarity index 55% rename from desktop/LanMountainDesktop/plugins/PluginCatalogEntry.cs rename to desktop/LanMountainDesktop/AirApps/AirAppCatalogEntry.cs index 7929089..34ad829 100644 --- a/desktop/LanMountainDesktop/plugins/PluginCatalogEntry.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppCatalogEntry.cs @@ -1,16 +1,16 @@ -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; -public enum PluginCatalogSourceKind +public enum AirAppCatalogSourceKind { Package = 0, Manifest = 1, - DevPlugin = 2 + DevAirApp = 2 } -public sealed record PluginCatalogEntry( - PluginManifest Manifest, +public sealed record AirAppCatalogEntry( + AirAppManifest Manifest, string SourcePath, bool IsPackage, bool IsEnabled, @@ -18,4 +18,4 @@ public sealed record PluginCatalogEntry( string? ErrorMessage, int SettingsPageCount, int WidgetCount, - bool IsDevPlugin = false); + bool IsDevAirApp = false); diff --git a/desktop/LanMountainDesktop/AirApps/AirAppContributions.cs b/desktop/LanMountainDesktop/AirApps/AirAppContributions.cs new file mode 100644 index 0000000..2c103d1 --- /dev/null +++ b/desktop/LanMountainDesktop/AirApps/AirAppContributions.cs @@ -0,0 +1,16 @@ +using LanMountainDesktop.AirApps; +using LanMountainDesktop.AirAppSdk; + +namespace LanMountainDesktop.Services; + +public sealed record AirAppSettingsSectionContribution( + LoadedAirApp AirApp, + AirAppSettingsSectionRegistration Registration); + +public sealed record AirAppDesktopComponentContribution( + LoadedAirApp AirApp, + AirAppComponentRegistration Registration); + +public sealed record AirAppDesktopComponentEditorContribution( + LoadedAirApp AirApp, + AirAppComponentEditorRegistration Registration); diff --git a/desktop/LanMountainDesktop/plugins/PluginExportRegistry.cs b/desktop/LanMountainDesktop/AirApps/AirAppExportRegistry.cs similarity index 60% rename from desktop/LanMountainDesktop/plugins/PluginExportRegistry.cs rename to desktop/LanMountainDesktop/AirApps/AirAppExportRegistry.cs index 2bf0044..b2b2ed9 100644 --- a/desktop/LanMountainDesktop/plugins/PluginExportRegistry.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppExportRegistry.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -internal sealed class PluginExportRegistry : IPluginExportRegistry +internal sealed class AirAppExportRegistry : IAirAppExportRegistry { private readonly object _gate = new(); - private readonly List _exports = []; + private readonly List _exports = []; - public IReadOnlyList GetExports() + public IReadOnlyList GetExports() { lock (_gate) { @@ -18,7 +18,7 @@ internal sealed class PluginExportRegistry : IPluginExportRegistry } } - public IReadOnlyList GetExports(Type contractType) + public IReadOnlyList GetExports(Type contractType) { ArgumentNullException.ThrowIfNull(contractType); @@ -30,26 +30,26 @@ internal sealed class PluginExportRegistry : IPluginExportRegistry } } - public PluginServiceExportDescriptor? GetExport(Type contractType, string providerPluginId) + public AirAppServiceExportDescriptor? GetExport(Type contractType, string providerAirAppId) { ArgumentNullException.ThrowIfNull(contractType); - ArgumentException.ThrowIfNullOrWhiteSpace(providerPluginId); + ArgumentException.ThrowIfNullOrWhiteSpace(providerAirAppId); lock (_gate) { return _exports.FirstOrDefault(descriptor => descriptor.ContractType == contractType && - string.Equals(descriptor.ProviderPluginId, providerPluginId, StringComparison.OrdinalIgnoreCase)); + string.Equals(descriptor.ProviderAirAppId, providerAirAppId, StringComparison.OrdinalIgnoreCase)); } } - public TContract? GetExport(string providerPluginId) + public TContract? GetExport(string providerAirAppId) where TContract : class { - return GetExport(typeof(TContract), providerPluginId)?.ServiceInstance as TContract; + return GetExport(typeof(TContract), providerAirAppId)?.ServiceInstance as TContract; } - public void ReplaceExports(string pluginId, IEnumerable descriptors) + public void ReplaceExports(string pluginId, IEnumerable descriptors) { ArgumentException.ThrowIfNullOrWhiteSpace(pluginId); ArgumentNullException.ThrowIfNull(descriptors); @@ -57,7 +57,7 @@ internal sealed class PluginExportRegistry : IPluginExportRegistry lock (_gate) { _exports.RemoveAll(descriptor => - string.Equals(descriptor.ProviderPluginId, pluginId, StringComparison.OrdinalIgnoreCase)); + string.Equals(descriptor.ProviderAirAppId, pluginId, StringComparison.OrdinalIgnoreCase)); _exports.AddRange(descriptors); } } @@ -69,7 +69,7 @@ internal sealed class PluginExportRegistry : IPluginExportRegistry lock (_gate) { _exports.RemoveAll(descriptor => - string.Equals(descriptor.ProviderPluginId, pluginId, StringComparison.OrdinalIgnoreCase)); + string.Equals(descriptor.ProviderAirAppId, pluginId, StringComparison.OrdinalIgnoreCase)); } } diff --git a/desktop/LanMountainDesktop/plugins/PluginLoadContext.cs b/desktop/LanMountainDesktop/AirApps/AirAppLoadContext.cs similarity index 89% rename from desktop/LanMountainDesktop/plugins/PluginLoadContext.cs rename to desktop/LanMountainDesktop/AirApps/AirAppLoadContext.cs index 4403f92..6ccdcf7 100644 --- a/desktop/LanMountainDesktop/plugins/PluginLoadContext.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppLoadContext.cs @@ -5,16 +5,16 @@ using System.Linq; using System.Reflection; using System.Runtime.Loader; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -public sealed class PluginLoadContext : AssemblyLoadContext +public sealed class AirAppLoadContext : AssemblyLoadContext { private readonly AssemblyDependencyResolver _resolver; private readonly HashSet _sharedAssemblyNames; - public PluginLoadContext(string mainAssemblyPath, IEnumerable? sharedAssemblyNames = null) + public AirAppLoadContext(string mainAssemblyPath, IEnumerable? sharedAssemblyNames = null) : base($"{Path.GetFileNameWithoutExtension(mainAssemblyPath)}_{Guid.NewGuid():N}", isCollectible: true) { ArgumentException.ThrowIfNullOrWhiteSpace(mainAssemblyPath); @@ -23,7 +23,7 @@ public sealed class PluginLoadContext : AssemblyLoadContext _resolver = new AssemblyDependencyResolver(MainAssemblyPath); _sharedAssemblyNames = new HashSet(StringComparer.OrdinalIgnoreCase) { - typeof(IPlugin).Assembly.GetName().Name! + typeof(IAirApp).Assembly.GetName().Name! }; if (sharedAssemblyNames is null) diff --git a/desktop/LanMountainDesktop/AirApps/AirAppLoadResult.cs b/desktop/LanMountainDesktop/AirApps/AirAppLoadResult.cs new file mode 100644 index 0000000..c13ecbf --- /dev/null +++ b/desktop/LanMountainDesktop/AirApps/AirAppLoadResult.cs @@ -0,0 +1,24 @@ +using System; + +using LanMountainDesktop.AirAppSdk; + +namespace LanMountainDesktop.AirApps; + +public sealed record AirAppLoadResult( + string SourcePath, + AirAppManifest? Manifest, + LoadedAirApp? LoadedAirApp, + Exception? Error) +{ + public bool IsSuccess => LoadedAirApp is not null && Error is null; + + public static AirAppLoadResult Success(string sourcePath, AirAppManifest manifest, LoadedAirApp loadedAirApp) + { + return new AirAppLoadResult(sourcePath, manifest, loadedAirApp, null); + } + + public static AirAppLoadResult Failure(string sourcePath, AirAppManifest? manifest, Exception error) + { + return new AirAppLoadResult(sourcePath, manifest, null, error); + } +} diff --git a/desktop/LanMountainDesktop/plugins/PluginLoader.cs b/desktop/LanMountainDesktop/AirApps/AirAppLoader.cs similarity index 68% rename from desktop/LanMountainDesktop/plugins/PluginLoader.cs rename to desktop/LanMountainDesktop/AirApps/AirAppLoader.cs index 503cbed..6b1d9ec 100644 --- a/desktop/LanMountainDesktop/plugins/PluginLoader.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppLoader.cs @@ -13,24 +13,24 @@ using System.Threading.Tasks; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.IPC; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using dotnetCampus.Ipc.CompilerServices.Attributes; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -public sealed class PluginLoader +public sealed class AirAppLoader { - private readonly PluginLoaderOptions _options; + private readonly AirAppLoaderOptions _options; - public PluginLoader(PluginLoaderOptions? options = null) + public AirAppLoader(AirAppLoaderOptions? options = null) { - _options = options ?? new PluginLoaderOptions(); + _options = options ?? new AirAppLoaderOptions(); } - public IReadOnlyList LoadAll( + public IReadOnlyList LoadAll( string pluginsRootDirectory, IServiceProvider? services = null, IReadOnlyDictionary? properties = null) @@ -39,18 +39,18 @@ public sealed class PluginLoader if (!Directory.Exists(pluginsRootDirectory)) { - return Array.Empty(); + return Array.Empty(); } - var results = new List(); + var results = new List(); var candidates = DiscoverCandidates(pluginsRootDirectory, results); - var selectedPluginIds = new HashSet(StringComparer.OrdinalIgnoreCase); + var selectedAirAppIds = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var candidate in candidates) { - if (!selectedPluginIds.Add(candidate.Manifest.Id)) + if (!selectedAirAppIds.Add(candidate.Manifest.Id)) { - results.Add(PluginLoadResult.Failure( + results.Add(AirAppLoadResult.Failure( candidate.SourcePath, candidate.Manifest, new InvalidOperationException( @@ -60,7 +60,7 @@ public sealed class PluginLoader results.Add(candidate.SourceKind switch { - PluginSourceKind.Package => LoadFromPackage( + AirAppSourceKind.Package => LoadFromPackage( candidate.SourcePath, pluginsRootDirectory, candidate.Manifest, @@ -77,31 +77,31 @@ public sealed class PluginLoader return results; } - public PluginLoadResult LoadFromManifest( + public AirAppLoadResult LoadFromManifest( string manifestPath, IServiceProvider? services = null, IReadOnlyDictionary? properties = null) { - PluginManifest? manifest = null; + AirAppManifest? manifest = null; try { - manifest = PluginManifest.Load(manifestPath); + manifest = AirAppManifest.Load(manifestPath); return LoadFromManifest(manifestPath, manifest, services, properties); } catch (Exception ex) { - return PluginLoadResult.Failure(Path.GetFullPath(manifestPath), manifest, ex); + return AirAppLoadResult.Failure(Path.GetFullPath(manifestPath), manifest, ex); } } - public PluginLoadResult LoadFromPackage( + public AirAppLoadResult LoadFromPackage( string packagePath, string pluginsRootDirectory, IServiceProvider? services = null, IReadOnlyDictionary? properties = null) { - PluginManifest? manifest = null; + AirAppManifest? manifest = null; try { @@ -110,13 +110,13 @@ public sealed class PluginLoader } catch (Exception ex) { - return PluginLoadResult.Failure(Path.GetFullPath(packagePath), manifest, ex); + return AirAppLoadResult.Failure(Path.GetFullPath(packagePath), manifest, ex); } } - public PluginLoadResult LoadFromAssembly( + public AirAppLoadResult LoadFromAssembly( string assemblyPath, - PluginManifest manifest, + AirAppManifest manifest, IServiceProvider? services = null, IReadOnlyDictionary? properties = null) { @@ -130,74 +130,76 @@ public sealed class PluginLoader return LoadCore(fullAssemblyPath, fullAssemblyPath, pluginDirectory, dataDirectory, manifest, services, properties); } - private PluginLoadResult LoadCore( + private AirAppLoadResult LoadCore( string sourcePath, string assemblyPath, string pluginDirectory, string dataDirectory, - PluginManifest manifest, + AirAppManifest manifest, IServiceProvider? services, IReadOnlyDictionary? properties) { - PluginLoadContext? loadContext = null; - IPlugin? plugin = null; - PluginRuntimeContext? runtimeContext = null; + AirAppLoadContext? loadContext = null; + IAirApp? plugin = null; + AirAppRuntimeContext? runtimeContext = null; ServiceProvider? pluginServices = null; IReadOnlyList hostedServices = Array.Empty(); try { Directory.CreateDirectory(dataDirectory); - ValidatePluginRuntimeAssets(manifest, assemblyPath, pluginDirectory, _options.IsDevMode); + ValidateAirAppRuntimeAssets(manifest, assemblyPath, pluginDirectory, _options.IsDevMode); AppLogger.Info( - "PluginLoader", - $"LoadCore starting. PluginId='{manifest.Id}'; AssemblyPath='{assemblyPath}'; PluginDirectory='{pluginDirectory}'; DataDirectory='{dataDirectory}'."); + "AirAppLoader", + $"LoadCore starting. AirAppId='{manifest.Id}'; AssemblyPath='{assemblyPath}'; AirAppDirectory='{pluginDirectory}'; DataDirectory='{dataDirectory}'."); - loadContext = new PluginLoadContext(assemblyPath, _options.SharedAssemblyNames); + loadContext = new AirAppLoadContext(assemblyPath, _options.SharedAssemblyNames); var assembly = loadContext.LoadFromAssemblyPath(assemblyPath); - AppLogger.Info("PluginLoader", $"Assembly loaded. PluginId='{manifest.Id}'; Assembly='{assembly.FullName}'."); - var pluginType = ResolvePluginType(assembly); - plugin = CreatePluginInstance(pluginType); - AppLogger.Info("PluginLoader", $"Plugin instance created. PluginId='{manifest.Id}'; PluginType='{pluginType.FullName}'."); + AppLogger.Info("AirAppLoader", $"Assembly loaded. AirAppId='{manifest.Id}'; Assembly='{assembly.FullName}'."); + var pluginType = ResolveAirAppType(assembly); + plugin = CreateAirAppInstance(pluginType); + AppLogger.Info("AirAppLoader", $"AirApp instance created. AirAppId='{manifest.Id}'; AirAppType='{pluginType.FullName}'."); runtimeContext = CreateRuntimeContext(manifest, pluginDirectory, dataDirectory, properties, services); var serviceCollection = CreateServiceCollection(runtimeContext, services); var hostBuilderContext = CreateHostBuilderContext(runtimeContext); plugin.Initialize(hostBuilderContext, serviceCollection); - AppLogger.Info("PluginLoader", $"Plugin Initialize completed. PluginId='{manifest.Id}'."); + AppLogger.Info("AirAppLoader", $"AirApp Initialize completed. AirAppId='{manifest.Id}'."); pluginServices = serviceCollection.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = false, ValidateOnBuild = true }); - AppLogger.Info("PluginLoader", $"Service provider built. PluginId='{manifest.Id}'."); + AppLogger.Info("AirAppLoader", $"Service provider built. AirAppId='{manifest.Id}'."); runtimeContext.SetServices(pluginServices); + plugin.OnStartedAsync(runtimeContext).GetAwaiter().GetResult(); + AppLogger.Info("AirAppLoader", $"AirApp OnStartedAsync completed. AirAppId='{manifest.Id}'."); var settingsSections = pluginServices - .GetServices() + .GetServices() .OrderBy(section => section.SortOrder) .ThenBy(section => section.TitleLocalizationKey, StringComparer.OrdinalIgnoreCase) .ToArray(); var desktopComponents = pluginServices - .GetServices() + .GetServices() .OrderBy(component => component.Category, StringComparer.OrdinalIgnoreCase) .ThenBy(component => component.DisplayName, StringComparer.OrdinalIgnoreCase) .ToArray(); var desktopComponentEditors = pluginServices - .GetServices() + .GetServices() .OrderBy(editor => editor.ComponentId, StringComparer.OrdinalIgnoreCase) .ToArray(); var exportedServices = ResolveExports(manifest, pluginServices); var publicIpcServices = ResolvePublicIpcServices(manifest, pluginServices); AppLogger.Info( - "PluginLoader", - $"Plugin contributions resolved. PluginId='{manifest.Id}'; SettingsSections={settingsSections.Length}; Widgets={desktopComponents.Length}; Editors={desktopComponentEditors.Length}; Exports={exportedServices.Count}; PublicIpcServices={publicIpcServices.Count}."); + "AirAppLoader", + $"AirApp contributions resolved. AirAppId='{manifest.Id}'; SettingsSections={settingsSections.Length}; Widgets={desktopComponents.Length}; Editors={desktopComponentEditors.Length}; Exports={exportedServices.Count}; PublicIpcServices={publicIpcServices.Count}."); hostedServices = pluginServices.GetServices().ToArray(); StartHostedServices(hostedServices); - AppLogger.Info("PluginLoader", $"Hosted services started. PluginId='{manifest.Id}'; HostedServices={hostedServices.Count}."); + AppLogger.Info("AirAppLoader", $"Hosted services started. AirAppId='{manifest.Id}'; HostedServices={hostedServices.Count}."); - var loadedPlugin = new LoadedPlugin( + var loadedAirApp = new LoadedAirApp( manifest, sourcePath, assemblyPath, @@ -213,7 +215,7 @@ public sealed class PluginLoader hostedServices, loadContext); - return PluginLoadResult.Success(sourcePath, manifest, loadedPlugin); + return AirAppLoadResult.Success(sourcePath, manifest, loadedAirApp); } catch (Exception ex) { @@ -222,13 +224,13 @@ public sealed class PluginLoader DisposeInstance(plugin); DisposeInstance(runtimeContext); loadContext?.Unload(); - return PluginLoadResult.Failure(sourcePath, manifest, ex); + return AirAppLoadResult.Failure(sourcePath, manifest, ex); } } - private PluginLoadResult LoadFromManifest( + private AirAppLoadResult LoadFromManifest( string manifestPath, - PluginManifest manifest, + AirAppManifest manifest, IServiceProvider? services, IReadOnlyDictionary? properties) { @@ -239,7 +241,7 @@ public sealed class PluginLoader if (!File.Exists(assemblyPath)) { throw new FileNotFoundException( - $"Plugin '{manifest.Id}' entrance assembly '{assemblyPath}' was not found.", + $"AirApp '{manifest.Id}' entrance assembly '{assemblyPath}' was not found.", assemblyPath); } @@ -250,14 +252,14 @@ public sealed class PluginLoader } catch (Exception ex) { - return PluginLoadResult.Failure(Path.GetFullPath(manifestPath), manifest, ex); + return AirAppLoadResult.Failure(Path.GetFullPath(manifestPath), manifest, ex); } } - private PluginLoadResult LoadFromPackage( + private AirAppLoadResult LoadFromPackage( string packagePath, string pluginsRootDirectory, - PluginManifest manifest, + AirAppManifest manifest, IServiceProvider? services, IReadOnlyDictionary? properties) { @@ -270,22 +272,22 @@ public sealed class PluginLoader if (!File.Exists(extractedManifestPath)) { throw new FileNotFoundException( - $"Plugin package '{fullPackagePath}' does not contain '{_options.ManifestFileName}'.", + $"AirApp package '{fullPackagePath}' does not contain '{_options.ManifestFileName}'.", extractedManifestPath); } - var extractedManifest = PluginManifest.Load(extractedManifestPath); + var extractedManifest = AirAppManifest.Load(extractedManifestPath); if (!string.Equals(extractedManifest.Id, manifest.Id, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException( - $"Plugin package '{fullPackagePath}' manifest id changed after extraction. Expected '{manifest.Id}', actual '{extractedManifest.Id}'."); + $"AirApp package '{fullPackagePath}' manifest id changed after extraction. Expected '{manifest.Id}', actual '{extractedManifest.Id}'."); } var assemblyPath = extractedManifest.ResolveEntranceAssemblyPath(extractedManifestPath); if (!File.Exists(assemblyPath)) { throw new FileNotFoundException( - $"Plugin '{extractedManifest.Id}' entrance assembly '{assemblyPath}' was not found after package extraction.", + $"AirApp '{extractedManifest.Id}' entrance assembly '{assemblyPath}' was not found after package extraction.", assemblyPath); } @@ -294,18 +296,18 @@ public sealed class PluginLoader } catch (Exception ex) { - return PluginLoadResult.Failure(Path.GetFullPath(packagePath), manifest, ex); + return AirAppLoadResult.Failure(Path.GetFullPath(packagePath), manifest, ex); } } - private PluginRuntimeContext CreateRuntimeContext( - PluginManifest manifest, + private AirAppRuntimeContext CreateRuntimeContext( + AirAppManifest manifest, string pluginDirectory, string dataDirectory, IReadOnlyDictionary? properties, IServiceProvider? hostServices) { - return new PluginRuntimeContext( + return new AirAppRuntimeContext( manifest, pluginDirectory, dataDirectory, @@ -314,24 +316,24 @@ public sealed class PluginLoader } private ServiceCollection CreateServiceCollection( - PluginRuntimeContext runtimeContext, + AirAppRuntimeContext runtimeContext, IServiceProvider? hostServices) { var services = new ServiceCollection(); services.AddSingleton(runtimeContext); - services.AddSingleton(runtimeContext); - services.AddSingleton(runtimeContext.Appearance); + services.AddSingleton(runtimeContext); + services.AddSingleton(runtimeContext.Appearance); services.AddSingleton(runtimeContext.Manifest); services.AddSingleton>(runtimeContext.Properties); - services.AddSingleton(); - services.AddSingleton(provider => - new PluginScopedSettingsService( + services.AddSingleton(); + services.AddSingleton(provider => + new AirAppScopedSettingsService( runtimeContext.Manifest.Id, provider.GetRequiredService())); - RegisterHostService(services, hostServices); + RegisterHostService(services, hostServices); RegisterHostService(services, hostServices); - RegisterHostService(services, hostServices); + RegisterHostService(services, hostServices); RegisterHostService(services, hostServices); RegisterHostService(services, hostServices); RegisterHostService(services, hostServices); @@ -343,7 +345,7 @@ public sealed class PluginLoader return services; } - private static PluginAppearanceSnapshot BuildAppearanceSnapshot(IServiceProvider? hostServices) + private static AirAppAppearanceSnapshot BuildAppearanceSnapshot(IServiceProvider? hostServices) { var defaultSnapshot = CreateDefaultAppearanceSnapshot(); @@ -363,14 +365,14 @@ public sealed class PluginLoader } catch (Exception ex) { - AppLogger.Warn("PluginLoader", "Failed to resolve host appearance snapshot for plugin runtime context.", ex); + AppLogger.Warn("AirAppLoader", "Failed to resolve host appearance snapshot for plugin runtime context.", ex); return defaultSnapshot; } } private static bool TryBuildAppearanceSnapshotFromMaterialColorService( IServiceProvider? hostServices, - out PluginAppearanceSnapshot snapshot) + out AirAppAppearanceSnapshot snapshot) { snapshot = default!; if (hostServices?.GetService(typeof(IMaterialColorService)) is not IMaterialColorService materialColorService) @@ -378,13 +380,13 @@ public sealed class PluginLoader return false; } - snapshot = PluginAppearanceSnapshotMapper.FromMaterialColorSnapshot(materialColorService.GetMaterialColorSnapshot()); + snapshot = AirAppAppearanceSnapshotMapper.FromMaterialColorSnapshot(materialColorService.GetMaterialColorSnapshot()); return true; } private static bool TryBuildCompatibilityAppearanceSnapshotFromAppearanceThemeService( IServiceProvider? hostServices, - out PluginAppearanceSnapshot snapshot) + out AirAppAppearanceSnapshot snapshot) { snapshot = default!; if (hostServices?.GetService(typeof(IAppearanceThemeService)) is not IAppearanceThemeService appearanceThemeService) @@ -392,14 +394,14 @@ public sealed class PluginLoader return false; } - snapshot = PluginAppearanceSnapshotMapper.FromCompatibilityAppearanceSnapshot(appearanceThemeService.GetCurrent()); + snapshot = AirAppAppearanceSnapshotMapper.FromCompatibilityAppearanceSnapshot(appearanceThemeService.GetCurrent()); return true; } - private static PluginAppearanceSnapshot CreateDefaultAppearanceSnapshot() + private static AirAppAppearanceSnapshot CreateDefaultAppearanceSnapshot() { - return new PluginAppearanceSnapshot( - CornerRadiusTokens: new PluginCornerRadiusTokens(6, 12, 14, 20, 28, 32, 36, 24), + return new AirAppAppearanceSnapshot( + CornerRadiusTokens: new AirAppCornerRadiusTokens(6, 12, 14, 20, 28, 32, 36, 24), ThemeVariant: "Unknown"); } @@ -412,13 +414,13 @@ public sealed class PluginLoader } } - private static HostBuilderContext CreateHostBuilderContext(PluginRuntimeContext runtimeContext) + private static HostBuilderContext CreateHostBuilderContext(AirAppRuntimeContext runtimeContext) { var hostBuilderContext = new HostBuilderContext(new Dictionary()); - hostBuilderContext.Properties["LanMountainDesktop.PluginManifest"] = runtimeContext.Manifest; - hostBuilderContext.Properties["LanMountainDesktop.PluginDirectory"] = runtimeContext.PluginDirectory; - hostBuilderContext.Properties["LanMountainDesktop.PluginDataDirectory"] = runtimeContext.DataDirectory; - hostBuilderContext.Properties["LanMountainDesktop.PluginRuntimeContext"] = runtimeContext; + hostBuilderContext.Properties["LanMountainDesktop.AirAppManifest"] = runtimeContext.Manifest; + hostBuilderContext.Properties["LanMountainDesktop.AirAppDirectory"] = runtimeContext.AirAppDirectory; + hostBuilderContext.Properties["LanMountainDesktop.AirAppDataDirectory"] = runtimeContext.DataDirectory; + hostBuilderContext.Properties["LanMountainDesktop.AirAppRuntimeContext"] = runtimeContext; foreach (var pair in runtimeContext.Properties) { @@ -431,48 +433,48 @@ public sealed class PluginLoader return hostBuilderContext; } - private static IReadOnlyList ResolveExports( - PluginManifest manifest, + private static IReadOnlyList ResolveExports( + AirAppManifest manifest, IServiceProvider services) { return services - .GetServices() + .GetServices() .Select(registration => { if (!IsSupportedExportContract(manifest, registration.ContractType)) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' exported contract '{registration.ContractType.FullName}', but export contracts must come from LanMountainDesktop.PluginSdk or a manifest-declared shared contract assembly."); + $"AirApp '{manifest.Id}' exported contract '{registration.ContractType.FullName}', but export contracts must come from LanMountainDesktop.AirAppSdk or a manifest-declared shared contract assembly."); } - return new PluginServiceExportDescriptor( + return new AirAppServiceExportDescriptor( manifest.Id, registration.ContractType, services.GetService(registration.ContractType) ?? throw new InvalidOperationException( - $"Plugin '{manifest.Id}' exported contract '{registration.ContractType.FullName}', but no singleton service instance was registered.")); + $"AirApp '{manifest.Id}' exported contract '{registration.ContractType.FullName}', but no singleton service instance was registered.")); }) .ToArray(); } - private static IReadOnlyList ResolvePublicIpcServices( - PluginManifest manifest, + private static IReadOnlyList ResolvePublicIpcServices( + AirAppManifest manifest, IServiceProvider services) { - var descriptors = new List(); + var descriptors = new List(); var seenKeys = new HashSet(StringComparer.OrdinalIgnoreCase); - foreach (var registration in services.GetServices()) + foreach (var registration in services.GetServices()) { var implementation = services.GetService(registration.ContractType) ?? throw new InvalidOperationException( - $"Plugin '{manifest.Id}' registered public IPC contract '{registration.ContractType.FullName}', but no singleton service instance was found."); + $"AirApp '{manifest.Id}' registered public IPC contract '{registration.ContractType.FullName}', but no singleton service instance was found."); AddDescriptor(registration.ContractType, implementation, registration.ObjectId, registration.NotifyIds); } - var builder = new RuntimePluginPublicIpcBuilder(services, AddDescriptor); - foreach (var contributor in services.GetServices()) + var builder = new RuntimeAirAppPublicIpcBuilder(services, AddDescriptor); + foreach (var contributor in services.GetServices()) { contributor.ConfigurePublicIpc(builder); } @@ -488,10 +490,10 @@ public sealed class PluginLoader if (!seenKeys.Add(dedupeKey)) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' registered duplicate public IPC contract '{contractType.FullName}' with object id '{normalizedObjectId}'."); + $"AirApp '{manifest.Id}' registered duplicate public IPC contract '{contractType.FullName}' with object id '{normalizedObjectId}'."); } - descriptors.Add(new PluginPublicIpcServiceDescriptor( + descriptors.Add(new AirAppPublicIpcServiceDescriptor( contractType, implementation, string.IsNullOrEmpty(normalizedObjectId) ? null : normalizedObjectId, @@ -502,24 +504,24 @@ public sealed class PluginLoader } } - private static void EnsurePublicIpcContract(PluginManifest manifest, Type contractType) + private static void EnsurePublicIpcContract(AirAppManifest manifest, Type contractType) { if (!contractType.IsInterface) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' public IPC contract '{contractType.FullName}' must be an interface."); + $"AirApp '{manifest.Id}' public IPC contract '{contractType.FullName}' must be an interface."); } if (!Attribute.IsDefined(contractType, typeof(IpcPublicAttribute), inherit: false)) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' public IPC contract '{contractType.FullName}' must be marked with '{nameof(IpcPublicAttribute)}'."); + $"AirApp '{manifest.Id}' public IPC contract '{contractType.FullName}' must be marked with '{nameof(IpcPublicAttribute)}'."); } } - private static bool IsSupportedExportContract(PluginManifest manifest, Type contractType) + private static bool IsSupportedExportContract(AirAppManifest manifest, Type contractType) { - if (contractType.Assembly == typeof(IPlugin).Assembly) + if (contractType.Assembly == typeof(IAirApp).Assembly) { return true; } @@ -533,7 +535,7 @@ public sealed class PluginLoader { foreach (var hostedService in hostedServices) { - AppLogger.Info("PluginLoader", $"Starting hosted service '{hostedService.GetType().FullName}'."); + AppLogger.Info("AirAppLoader", $"Starting hosted service '{hostedService.GetType().FullName}'."); hostedService.StartAsync(CancellationToken.None).GetAwaiter().GetResult(); } } @@ -553,11 +555,11 @@ public sealed class PluginLoader } } - private IReadOnlyList DiscoverCandidates( + private IReadOnlyList DiscoverCandidates( string pluginsRootDirectory, - List preparationFailures) + List preparationFailures) { - var candidates = new List(); + var candidates = new List(); foreach (var packagePath in EnumerateCandidatePaths( pluginsRootDirectory, @@ -566,11 +568,11 @@ public sealed class PluginLoader try { var manifest = ReadManifestFromPackage(packagePath); - candidates.Add(new PluginCandidate(Path.GetFullPath(packagePath), manifest, PluginSourceKind.Package)); + candidates.Add(new AirAppCandidate(Path.GetFullPath(packagePath), manifest, AirAppSourceKind.Package)); } catch (Exception ex) { - preparationFailures.Add(PluginLoadResult.Failure(Path.GetFullPath(packagePath), null, ex)); + preparationFailures.Add(AirAppLoadResult.Failure(Path.GetFullPath(packagePath), null, ex)); } } @@ -578,12 +580,12 @@ public sealed class PluginLoader { try { - var manifest = PluginManifest.Load(manifestPath); - candidates.Add(new PluginCandidate(Path.GetFullPath(manifestPath), manifest, PluginSourceKind.Manifest)); + var manifest = AirAppManifest.Load(manifestPath); + candidates.Add(new AirAppCandidate(Path.GetFullPath(manifestPath), manifest, AirAppSourceKind.Manifest)); } catch (Exception ex) { - preparationFailures.Add(PluginLoadResult.Failure(Path.GetFullPath(manifestPath), null, ex)); + preparationFailures.Add(AirAppLoadResult.Failure(Path.GetFullPath(manifestPath), null, ex)); } } @@ -604,14 +606,14 @@ public sealed class PluginLoader .OrderBy(path => path, StringComparer.OrdinalIgnoreCase); } - private PluginManifest ReadManifestFromPackage(string packagePath) + private AirAppManifest ReadManifestFromPackage(string packagePath) { ArgumentException.ThrowIfNullOrWhiteSpace(packagePath); var fullPackagePath = Path.GetFullPath(packagePath); if (!File.Exists(fullPackagePath)) { - throw new FileNotFoundException($"Plugin package '{fullPackagePath}' was not found.", fullPackagePath); + throw new FileNotFoundException($"AirApp package '{fullPackagePath}' was not found.", fullPackagePath); } using var archive = ZipFile.OpenRead(fullPackagePath); @@ -624,17 +626,17 @@ public sealed class PluginLoader if (manifestEntries.Length == 0) { throw new InvalidOperationException( - $"Plugin package '{fullPackagePath}' does not contain '{_options.ManifestFileName}'."); + $"AirApp package '{fullPackagePath}' does not contain '{_options.ManifestFileName}'."); } if (manifestEntries.Length > 1) { throw new InvalidOperationException( - $"Plugin package '{fullPackagePath}' contains multiple '{_options.ManifestFileName}' files."); + $"AirApp package '{fullPackagePath}' contains multiple '{_options.ManifestFileName}' files."); } using var stream = manifestEntries[0].Open(); - return PluginManifest.Load(stream, $"{fullPackagePath}!/{manifestEntries[0].FullName}"); + return AirAppManifest.Load(stream, $"{fullPackagePath}!/{manifestEntries[0].FullName}"); } private string ExtractPackage(string packagePath, string pluginsRootDirectory) @@ -645,13 +647,13 @@ public sealed class PluginLoader if (ShouldSkipExtraction(packagePath, extractionDirectory)) { AppLogger.Info( - "PluginLoader", + "AirAppLoader", $"Skipping extraction for '{packagePath}'. Cache is up-to-date."); return extractionDirectory; } AppLogger.Info( - "PluginLoader", + "AirAppLoader", $"Extracting package '{packagePath}' to '{extractionDirectory}'."); RecreateDirectory(extractionDirectory); ZipFile.ExtractToDirectory(packagePath, extractionDirectory, overwriteFiles: true); @@ -675,7 +677,7 @@ public sealed class PluginLoader $"{packageName}_{packageHash}"); } - private string GetPackagedDataDirectory(string pluginsRootDirectory, PluginManifest manifest) + private string GetPackagedDataDirectory(string pluginsRootDirectory, AirAppManifest manifest) { return Path.Combine( GetRuntimeRootDirectory(pluginsRootDirectory), @@ -692,7 +694,7 @@ public sealed class PluginLoader { if (Directory.Exists(directoryPath)) { - FileOperationRetryHelper.DeleteDirectoryWithRetry(directoryPath, recursive: true, "PluginLoader"); + FileOperationRetryHelper.DeleteDirectoryWithRetry(directoryPath, recursive: true, "AirAppLoader"); } Directory.CreateDirectory(directoryPath); @@ -753,7 +755,7 @@ public sealed class PluginLoader catch (Exception ex) { AppLogger.Warn( - "PluginLoader", + "AirAppLoader", $"Failed to read extraction metadata for '{packagePath}'. Will re-extract.", ex); return false; @@ -783,7 +785,7 @@ public sealed class PluginLoader catch (Exception ex) { AppLogger.Warn( - "PluginLoader", + "AirAppLoader", $"Failed to save extraction metadata for '{packagePath}'.", ex); } @@ -822,8 +824,8 @@ public sealed class PluginLoader return new ReadOnlyDictionary(map); } - private static void ValidatePluginRuntimeAssets( - PluginManifest manifest, + private static void ValidateAirAppRuntimeAssets( + AirAppManifest manifest, string assemblyPath, string pluginDirectory, bool isDevMode) @@ -834,13 +836,13 @@ public sealed class PluginLoader if (isDevMode) { AppLogger.Warn( - "PluginLoader", - $"Plugin '{manifest.Id}' is missing '{Path.GetFileName(depsFilePath)}'. In developer mode this is allowed, but dependency resolution may fail at runtime."); + "AirAppLoader", + $"AirApp '{manifest.Id}' is missing '{Path.GetFileName(depsFilePath)}'. In developer mode this is allowed, but dependency resolution may fail at runtime."); } else { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' targets API {PluginSdkInfo.ApiVersion} and must include '{Path.GetFileName(depsFilePath)}' next to its main assembly."); + $"AirApp '{manifest.Id}' targets API {AirAppSdkInfo.ApiVersion} and must include '{Path.GetFileName(depsFilePath)}' next to its main assembly."); } } @@ -849,15 +851,15 @@ public sealed class PluginLoader !Directory.EnumerateFiles(runtimesDirectory, "*", SearchOption.AllDirectories).Any()) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' contains an empty 'runtimes' directory. Native/runtime assets must be packaged together with the plugin."); + $"AirApp '{manifest.Id}' contains an empty 'runtimes' directory. Native/runtime assets must be packaged together with the plugin."); } } - private static Type ResolvePluginType(Assembly assembly) + private static Type ResolveAirAppType(Assembly assembly) { var candidateTypes = GetLoadableTypes(assembly) .Where(type => - typeof(IPlugin).IsAssignableFrom(type) && + typeof(IAirApp).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface && !type.ContainsGenericParameters) @@ -866,11 +868,11 @@ public sealed class PluginLoader if (candidateTypes.Length == 0) { throw new InvalidOperationException( - $"Assembly '{assembly.Location}' does not contain a concrete type implementing '{nameof(IPlugin)}'."); + $"Assembly '{assembly.Location}' does not contain a concrete type implementing '{nameof(IAirApp)}'."); } var attributedTypes = candidateTypes - .Where(type => type.IsDefined(typeof(PluginEntranceAttribute), inherit: false)) + .Where(type => type.IsDefined(typeof(AirAppEntranceAttribute), inherit: false)) .ToArray(); if (attributedTypes.Length == 1) @@ -881,7 +883,7 @@ public sealed class PluginLoader if (attributedTypes.Length > 1) { throw new InvalidOperationException( - $"Assembly '{assembly.Location}' contains multiple plugin entrance types. Mark only one type with '{nameof(PluginEntranceAttribute)}'."); + $"Assembly '{assembly.Location}' contains multiple plugin entrance types. Mark only one type with '{nameof(AirAppEntranceAttribute)}'."); } if (candidateTypes.Length == 1) @@ -890,18 +892,18 @@ public sealed class PluginLoader } throw new InvalidOperationException( - $"Assembly '{assembly.Location}' contains multiple '{nameof(IPlugin)}' implementations. Mark the intended entrance type with '{nameof(PluginEntranceAttribute)}'."); + $"Assembly '{assembly.Location}' contains multiple '{nameof(IAirApp)}' implementations. Mark the intended entrance type with '{nameof(AirAppEntranceAttribute)}'."); } - private static IPlugin CreatePluginInstance(Type pluginType) + private static IAirApp CreateAirAppInstance(Type pluginType) { if (pluginType.GetConstructor(Type.EmptyTypes) is null) { throw new InvalidOperationException( - $"Plugin type '{pluginType.FullName}' must expose a public parameterless constructor."); + $"AirApp type '{pluginType.FullName}' must expose a public parameterless constructor."); } - if (Activator.CreateInstance(pluginType) is not IPlugin plugin) + if (Activator.CreateInstance(pluginType) is not IAirApp plugin) { throw new InvalidOperationException( $"Failed to create plugin instance of type '{pluginType.FullName}'."); @@ -933,7 +935,7 @@ public sealed class PluginLoader catch (Exception disposeError) { System.Diagnostics.Debug.WriteLine( - $"[PluginLoader] Disposal of '{instance.GetType().FullName}' failed: {disposeError}"); + $"[AirAppLoader] Disposal of '{instance.GetType().FullName}' failed: {disposeError}"); } } @@ -960,37 +962,70 @@ public sealed class PluginLoader } } - private sealed class PluginRuntimeContext : IPluginRuntimeContext + private sealed class AirAppRuntimeContext : IAirAppRuntimeContext { - private readonly PluginAppearanceContext _appearanceContext; + private readonly AirAppAppearanceContext _appearanceContext; + private readonly AirAppMessageBus _messageBus; + private readonly IAirAppLogger _logger; + private readonly List _runtimeComponents = []; + private readonly List _runtimeWindows = []; - public PluginRuntimeContext( - PluginManifest manifest, + public AirAppRuntimeContext( + AirAppManifest manifest, string pluginDirectory, string dataDirectory, IReadOnlyDictionary properties, - PluginAppearanceSnapshot appearanceSnapshot) + AirAppAppearanceSnapshot appearanceSnapshot) { Manifest = manifest; - PluginDirectory = pluginDirectory; + AirAppDirectory = pluginDirectory; DataDirectory = dataDirectory; + CacheDirectory = Path.Combine(pluginDirectory, "Cache"); Properties = properties; - _appearanceContext = new PluginAppearanceContext(appearanceSnapshot); + _appearanceContext = new AirAppAppearanceContext(appearanceSnapshot); Appearance = _appearanceContext; + _messageBus = new AirAppMessageBus(); + _logger = new AirAppRuntimeLogger(manifest.Id); + MessageBus = _messageBus; + Logger = _logger; + Lifetime = NoOpHostApplicationLifetime.Instance; Services = NullServiceProvider.Instance; } - public PluginManifest Manifest { get; } + public AirAppManifest Manifest { get; } - public string PluginDirectory { get; } + public string AirAppDirectory { get; } public string DataDirectory { get; } + public string CacheDirectory { get; } + public IServiceProvider Services { get; private set; } public IReadOnlyDictionary Properties { get; } - public IPluginAppearanceContext Appearance { get; } + public IHostApplicationLifetime Lifetime { get; } + + public IAirAppMessageBus MessageBus { get; } + + public IAirAppAppearanceContext Appearance { get; } + + public IAirAppLogger Logger { get; } + + /// + /// 由宿主注入的窗口打开处理器(AirAppHost 第三方窗口链路,Stage 3 接入)。 + /// 未设置时 会抛出 NotSupportedException。 + /// + internal Func>? OpenWindowHandler { get; set; } + + /// + /// 由宿主注入的窗口关闭处理器。 + /// + internal Action? CloseWindowHandler { get; set; } + + internal IReadOnlyList RuntimeComponents => _runtimeComponents; + + internal IReadOnlyList RuntimeWindows => _runtimeWindows; public T? GetService() { @@ -1011,6 +1046,49 @@ public sealed class PluginLoader return false; } + public async Task OpenWindowAsync(string windowId) + { + var handler = OpenWindowHandler; + if (handler is null) + { + throw new NotSupportedException( + $"AirApp '{Manifest.Id}' requested to open window '{windowId}', but the host does not support in-process window opening. Use an isolated window AirApp instead."); + } + + return await handler(windowId).ConfigureAwait(false); + } + + public void CloseWindow(string windowId) + { + var closer = CloseWindowHandler; + if (closer is null) + { + throw new NotSupportedException( + $"AirApp '{Manifest.Id}' requested to close window '{windowId}', but the host does not support in-process window closing."); + } + + closer(windowId); + } + + public void RegisterComponent(AirAppComponentOptions options) + { + ArgumentNullException.ThrowIfNull(options); + _runtimeComponents.Add(options); + } + + public void RegisterWindow(string id, string name, Type windowType) + { + _runtimeWindows.Add(new AirAppWindowRegistration(id, name, windowType)); + } + + public void RegisterService() + where TService : class + where TImplementation : class, TService + { + throw new InvalidOperationException( + $"AirApp '{Manifest.Id}' called RegisterService after startup. Register services in Initialize via IServiceCollection instead."); + } + public void SetServices(IServiceProvider services) { Services = services ?? throw new ArgumentNullException(nameof(services)); @@ -1019,15 +1097,57 @@ public sealed class PluginLoader /// /// 更新外观快照并通知插件。 /// - internal void UpdateAppearanceSnapshot(PluginAppearanceSnapshot newSnapshot, IReadOnlyCollection changedProperties) + internal void UpdateAppearanceSnapshot(AirAppAppearanceSnapshot newSnapshot, IReadOnlyCollection changedProperties) { _appearanceContext.UpdateSnapshot(newSnapshot, changedProperties); } } - private sealed class PluginMessageBus : IPluginMessageBus, IDisposable + private sealed class AirAppRuntimeLogger : IAirAppLogger + { + private readonly string _category; + + public AirAppRuntimeLogger(string airAppId) + { + _category = $"AirApp:{airAppId}"; + } + + public void Debug(string message) => AppLogger.Info(_category, message); + + public void Info(string message) => AppLogger.Info(_category, message); + + public void Warn(string message) => AppLogger.Warn(_category, message); + + public void Warn(string message, Exception exception) => AppLogger.Warn(_category, message, exception); + + public void Error(string message) => AppLogger.Error(_category, message); + + public void Error(string message, Exception exception) => AppLogger.Error(_category, message, exception); + } + + private sealed class NoOpHostApplicationLifetime : IHostApplicationLifetime + { + public static NoOpHostApplicationLifetime Instance { get; } = new(); + + private NoOpHostApplicationLifetime() + { + } + + public CancellationToken ApplicationStarted => CancellationToken.None; + + public CancellationToken ApplicationStopping => CancellationToken.None; + + public CancellationToken ApplicationStopped => CancellationToken.None; + + public void StopApplication() + { + } + } + + private sealed class AirAppMessageBus : IAirAppMessageBus, IDisposable { private readonly Dictionary> _subscriptions = []; + private readonly Dictionary> _topicSubscriptions = []; private readonly object _gate = new(); private int _disposed; @@ -1036,7 +1156,7 @@ public sealed class PluginLoader ArgumentNullException.ThrowIfNull(handler); if (Volatile.Read(ref _disposed) != 0) { - throw new ObjectDisposedException(nameof(PluginMessageBus)); + throw new ObjectDisposedException(nameof(AirAppMessageBus)); } var subscription = new Subscription(this, typeof(TMessage), message => handler((TMessage)message!)); @@ -1081,11 +1201,72 @@ public sealed class PluginLoader catch (Exception ex) { System.Diagnostics.Debug.WriteLine( - $"[PluginMessageBus] Handler for '{typeof(TMessage).FullName}' failed: {ex}"); + $"[AirAppMessageBus] Handler for '{typeof(TMessage).FullName}' failed: {ex}"); } } } + public void Publish(string topic, object? payload = null) + { + if (Volatile.Read(ref _disposed) != 0) + { + return; + } + + Subscription[] handlers; + lock (_gate) + { + if (!_topicSubscriptions.TryGetValue(topic, out var subscriptions) || subscriptions.Count == 0) + { + return; + } + + handlers = subscriptions.ToArray(); + } + + foreach (var handler in handlers) + { + try + { + handler.Invoke(payload); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine( + $"[AirAppMessageBus] Handler for topic '{topic}' failed: {ex}"); + } + } + } + + public IDisposable Subscribe(string topic, Action handler) + { + ArgumentNullException.ThrowIfNull(handler); + if (Volatile.Read(ref _disposed) != 0) + { + throw new ObjectDisposedException(nameof(AirAppMessageBus)); + } + + var subscription = new Subscription(this, typeof(object), handler, topic); + lock (_gate) + { + if (!_topicSubscriptions.TryGetValue(topic, out var handlers)) + { + handlers = []; + _topicSubscriptions[topic] = handlers; + } + + handlers.Add(subscription); + } + + return subscription; + } + + public IDisposable Subscribe(string topic, Action handler) + { + ArgumentNullException.ThrowIfNull(handler); + return Subscribe(topic, message => handler(message is T typed ? typed : default)); + } + public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) != 0) @@ -1096,6 +1277,7 @@ public sealed class PluginLoader lock (_gate) { _subscriptions.Clear(); + _topicSubscriptions.Clear(); } } @@ -1103,6 +1285,20 @@ public sealed class PluginLoader { lock (_gate) { + if (subscription.Topic is not null) + { + if (_topicSubscriptions.TryGetValue(subscription.Topic, out var topicHandlers)) + { + topicHandlers.Remove(subscription); + if (topicHandlers.Count == 0) + { + _topicSubscriptions.Remove(subscription.Topic); + } + } + + return; + } + if (!_subscriptions.TryGetValue(subscription.MessageType, out var handlers)) { return; @@ -1118,16 +1314,21 @@ public sealed class PluginLoader private sealed class Subscription : IDisposable { - private readonly PluginMessageBus _owner; + private readonly AirAppMessageBus _owner; private int _disposed; - public Subscription(PluginMessageBus owner, Type messageType, Action handler) + public Subscription(AirAppMessageBus owner, Type messageType, Action handler, string? topic = null) { _owner = owner; + _topic = topic; MessageType = messageType; Handler = handler; } + private readonly string? _topic; + + public string? Topic => _topic; + public Type MessageType { get; } public Action Handler { get; } @@ -1168,23 +1369,23 @@ public sealed class PluginLoader } } - private enum PluginSourceKind + private enum AirAppSourceKind { Package = 0, Manifest = 1 } - private sealed record PluginCandidate( + private sealed record AirAppCandidate( string SourcePath, - PluginManifest Manifest, - PluginSourceKind SourceKind); + AirAppManifest Manifest, + AirAppSourceKind SourceKind); - private sealed class RuntimePluginPublicIpcBuilder : IPluginPublicIpcBuilder + private sealed class RuntimeAirAppPublicIpcBuilder : IAirAppPublicIpcBuilder { private readonly IServiceProvider _services; private readonly Action?> _register; - public RuntimePluginPublicIpcBuilder( + public RuntimeAirAppPublicIpcBuilder( IServiceProvider services, Action?> register) { @@ -1192,19 +1393,19 @@ public sealed class PluginLoader _register = register; } - public IPluginPublicIpcBuilder AddService( + public IAirAppPublicIpcBuilder AddService( string? objectId = null, IEnumerable? notifyIds = null) where TContract : class { var implementation = _services.GetService(typeof(TContract)) ?? throw new InvalidOperationException( - $"Plugin public IPC contributor requested contract '{typeof(TContract).FullName}', but no singleton service was registered."); + $"AirApp public IPC contributor requested contract '{typeof(TContract).FullName}', but no singleton service was registered."); _register(typeof(TContract), implementation, objectId, notifyIds); return this; } - public IPluginPublicIpcBuilder AddService( + public IAirAppPublicIpcBuilder AddService( Type contractType, object implementation, string? objectId = null, diff --git a/desktop/LanMountainDesktop/AirApps/AirAppLoaderOptions.cs b/desktop/LanMountainDesktop/AirApps/AirAppLoaderOptions.cs new file mode 100644 index 0000000..b603969 --- /dev/null +++ b/desktop/LanMountainDesktop/AirApps/AirAppLoaderOptions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +using LanMountainDesktop.AirAppSdk; + +namespace LanMountainDesktop.AirApps; + +public sealed class AirAppLoaderOptions +{ + public string ManifestFileName { get; init; } = AirAppSdkInfo.ManifestFileName; + + public string PackageFileExtension { get; init; } = AirAppSdkInfo.PackageFileExtension; + + public string DataDirectoryName { get; init; } = AirAppSdkInfo.DataDirectoryName; + + public string RuntimeDirectoryName { get; init; } = AirAppSdkInfo.RuntimeDirectoryName; + + public string ExtractedPackagesDirectoryName { get; init; } = AirAppSdkInfo.ExtractedPackagesDirectoryName; + + public string PackagedDataDirectoryName { get; init; } = AirAppSdkInfo.PackagedDataDirectoryName; + + public bool IsDevMode { get; init; } + + public ISet SharedAssemblyNames { get; } = new HashSet(StringComparer.OrdinalIgnoreCase) + { + typeof(IAirApp).Assembly.GetName().Name! + }; +} diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketAssetCacheService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketAssetCacheService.cs similarity index 96% rename from desktop/LanMountainDesktop/plugins/PluginMarketAssetCacheService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketAssetCacheService.cs index a0080f2..355d095 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketAssetCacheService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketAssetCacheService.cs @@ -5,16 +5,16 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; /// /// Local disk cache for plugin market assets (README markdown and icon images). /// Cache validity is driven by index refresh: an entry is reused while its source URL and /// plugin version are unchanged, and refreshed only when the market index reports a change. /// -public sealed class PluginMarketAssetCacheService : IDisposable +public sealed class AirAppMarketAssetCacheService : IDisposable { private static readonly JsonSerializerOptions ManifestSerializerOptions = new() { @@ -29,7 +29,7 @@ public sealed class PluginMarketAssetCacheService : IDisposable private readonly object _manifestGate = new(); private AssetCacheManifest _manifest; - public PluginMarketAssetCacheService(string pluginMarketDataDirectory) + public AirAppMarketAssetCacheService(string pluginMarketDataDirectory) { ArgumentException.ThrowIfNullOrWhiteSpace(pluginMarketDataDirectory); @@ -150,7 +150,7 @@ public sealed class PluginMarketAssetCacheService : IDisposable } if (!string.Equals(entry.SourceUrl, sourceUrl, StringComparison.OrdinalIgnoreCase) || - !string.Equals(entry.PluginVersion, pluginVersion, StringComparison.OrdinalIgnoreCase)) + !string.Equals(entry.AirAppVersion, pluginVersion, StringComparison.OrdinalIgnoreCase)) { return null; } @@ -317,7 +317,7 @@ public sealed class PluginMarketAssetCacheService : IDisposable { AssetKind = assetKind; SourceUrl = sourceUrl; - PluginVersion = pluginVersion; + AirAppVersion = pluginVersion; CachedAt = cachedAt; } @@ -328,7 +328,7 @@ public sealed class PluginMarketAssetCacheService : IDisposable public string SourceUrl { get; init; } = string.Empty; [JsonPropertyName("pluginVersion")] - public string PluginVersion { get; init; } = string.Empty; + public string AirAppVersion { get; init; } = string.Empty; [JsonPropertyName("cachedAt")] public DateTimeOffset CachedAt { get; init; } diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketCacheService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketCacheService.cs similarity index 95% rename from desktop/LanMountainDesktop/plugins/PluginMarketCacheService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketCacheService.cs index 2614100..0ff4457 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketCacheService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketCacheService.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; internal sealed class AirAppMarketCacheService { diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketIconService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketIconService.cs similarity index 90% rename from desktop/LanMountainDesktop/plugins/PluginMarketIconService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketIconService.cs index 811777f..22a801a 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketIconService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketIconService.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Avalonia.Media.Imaging; using LanMountainDesktop.Services.Settings; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; /// /// Loads plugin icons from the local workspace, the on-disk asset cache, or the network, @@ -14,7 +14,7 @@ namespace LanMountainDesktop.Services.PluginMarket; /// public sealed class AirAppMarketIconService : IDisposable { - private readonly PluginMarketAssetCacheService? _cache; + private readonly AirAppMarketAssetCacheService? _cache; private readonly HttpClient _httpClient; public AirAppMarketIconService() @@ -22,18 +22,18 @@ public sealed class AirAppMarketIconService : IDisposable { } - public AirAppMarketIconService(PluginMarketAssetCacheService? cache) + public AirAppMarketIconService(AirAppMarketAssetCacheService? cache) { _cache = cache; _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(20) }; - _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0"); + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-AirAppMarketplace/1.0"); } public async Task LoadAsync( - PluginCatalogItemInfo plugin, + AirAppCatalogItemInfo plugin, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(plugin); diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketIndexService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketIndexService.cs similarity index 97% rename from desktop/LanMountainDesktop/plugins/PluginMarketIndexService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketIndexService.cs index eb68e97..e706885 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketIndexService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketIndexService.cs @@ -5,7 +5,7 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; internal sealed class AirAppMarketIndexService : IDisposable { @@ -19,7 +19,7 @@ internal sealed class AirAppMarketIndexService : IDisposable { Timeout = TimeSpan.FromSeconds(20) }; - _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0"); + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-AirAppMarketplace/1.0"); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); } diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketInstallService.cs similarity index 79% rename from desktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketInstallService.cs index d5cf18f..1b62db5 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketInstallService.cs @@ -7,23 +7,23 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Security.Cryptography; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; internal sealed class AirAppMarketInstallService : IDisposable { - private readonly PluginRuntimeService _runtime; + private readonly AirAppRuntimeService _runtime; private readonly HttpClient _httpClient; private readonly ResumableDownloadService _downloadService; private readonly AirAppMarketReleaseResolverService _releaseResolverService; - private readonly PendingPluginUpgradeService _pendingUpgradeService; - private readonly ElevatedPluginInstallService _elevatedInstallService = new(); + private readonly PendingAirAppUpgradeService _pendingUpgradeService; + private readonly ElevatedAirAppInstallService _elevatedInstallService = new(); private readonly string _downloadsDirectory; private readonly Version? _hostVersion; - public AirAppMarketInstallService(PluginRuntimeService runtime, string dataDirectory) + public AirAppMarketInstallService(AirAppRuntimeService runtime, string dataDirectory) { _runtime = runtime; _downloadsDirectory = ResolveDownloadsDirectory(dataDirectory); @@ -31,15 +31,15 @@ internal sealed class AirAppMarketInstallService : IDisposable { Timeout = TimeSpan.FromMinutes(2) }; - _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0"); + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-AirAppMarketplace/1.0"); _downloadService = new ResumableDownloadService(_httpClient); _releaseResolverService = new AirAppMarketReleaseResolverService(_httpClient); - _pendingUpgradeService = new PendingPluginUpgradeService(runtime.PluginsDirectory); + _pendingUpgradeService = new PendingAirAppUpgradeService(runtime.AirAppsDirectory); _hostVersion = typeof(App).Assembly.GetName().Version; } public async Task InstallAsync( - AirAppMarketPluginEntry plugin, + AirAppMarketAirAppEntry plugin, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(plugin); @@ -51,37 +51,37 @@ internal sealed class AirAppMarketInstallService : IDisposable return new AirAppMarketInstallResult( false, null, - "Plugin does not declare any package sources."); + "AirApp does not declare any package sources."); } AppLogger.Info( - "PluginMarket", - $"Starting install. PluginId='{plugin.Id}'; Version='{plugin.Version}'; Sources='{string.Join(", ", sources.Select(source => source.SourceKind.ToString()))}'."); + "AirAppMarket", + $"Starting install. AirAppId='{plugin.Id}'; Version='{plugin.Version}'; Sources='{string.Join(", ", sources.Select(source => source.SourceKind.ToString()))}'."); var compatibilityError = ValidateCompatibility(plugin); if (!string.IsNullOrWhiteSpace(compatibilityError)) { - AppLogger.Warn("PluginMarket", $"Compatibility check failed. PluginId='{plugin.Id}'; Error='{compatibilityError}'."); + AppLogger.Warn("AirAppMarket", $"Compatibility check failed. AirAppId='{plugin.Id}'; Error='{compatibilityError}'."); return new AirAppMarketInstallResult(false, null, compatibilityError); } return await StageInstallOrUpgradeAsync( plugin, sources, - IsPluginInstalled(plugin.Id), + IsAirAppInstalled(plugin.Id), cancellationToken).ConfigureAwait(false); } private async Task StageInstallOrUpgradeAsync( - AirAppMarketPluginEntry plugin, - IReadOnlyList sources, + AirAppMarketAirAppEntry plugin, + IReadOnlyList sources, bool isUpgrade, CancellationToken cancellationToken) { - var canWritePluginsDirectory = PluginInstallTargetAccess.CanWriteDirectory(_runtime.PluginsDirectory); + var canWriteAirAppsDirectory = AirAppInstallTargetAccess.CanWriteDirectory(_runtime.AirAppsDirectory); AppLogger.Info( - "PluginMarket", - $"Detected {(isUpgrade ? "upgrade" : "new install")} scenario. Downloading package for {(canWritePluginsDirectory ? "deferred" : "elevated")} install. PluginId='{plugin.Id}'; PluginsDirectory='{_runtime.PluginsDirectory}'; CanWritePluginsDirectory={canWritePluginsDirectory}."); + "AirAppMarket", + $"Detected {(isUpgrade ? "upgrade" : "new install")} scenario. Downloading package for {(canWriteAirAppsDirectory ? "deferred" : "elevated")} install. AirAppId='{plugin.Id}'; AirAppsDirectory='{_runtime.AirAppsDirectory}'; CanWriteAirAppsDirectory={canWriteAirAppsDirectory}."); var sourceErrors = new List(); foreach (var source in sources) @@ -100,11 +100,11 @@ internal sealed class AirAppMarketInstallService : IDisposable try { var manifest = ReadManifestFromPackage(downloadResult.PackagePath); - if (!canWritePluginsDirectory) + if (!canWriteAirAppsDirectory) { var elevatedResult = await _elevatedInstallService.InstallAsync( downloadResult.PackagePath, - _runtime.PluginsDirectory, + _runtime.AirAppsDirectory, cancellationToken).ConfigureAwait(false); if (!elevatedResult.Success) { @@ -113,8 +113,8 @@ internal sealed class AirAppMarketInstallService : IDisposable } AppLogger.Info( - "PluginMarket", - $"Plugin package installed through elevated installer. PluginId='{manifest.Id}'; Version='{manifest.Version ?? plugin.Version}'; PackagePath='{downloadResult.PackagePath}'; IsUpgrade={isUpgrade}."); + "AirAppMarket", + $"AirApp package installed through elevated installer. AirAppId='{manifest.Id}'; Version='{manifest.Version ?? plugin.Version}'; PackagePath='{downloadResult.PackagePath}'; IsUpgrade={isUpgrade}."); return new AirAppMarketInstallResult(true, manifest, null, RestartRequired: true); } @@ -125,8 +125,8 @@ internal sealed class AirAppMarketInstallService : IDisposable manifest.Version ?? plugin.Version); AppLogger.Info( - "PluginMarket", - $"Plugin package queued for next restart. PluginId='{manifest.Id}'; Version='{manifest.Version ?? plugin.Version}'; PackagePath='{downloadResult.PackagePath}'; IsUpgrade={isUpgrade}."); + "AirAppMarket", + $"AirApp package queued for next restart. AirAppId='{manifest.Id}'; Version='{manifest.Version ?? plugin.Version}'; PackagePath='{downloadResult.PackagePath}'; IsUpgrade={isUpgrade}."); return new AirAppMarketInstallResult(true, manifest, null, RestartRequired: true); } @@ -143,28 +143,28 @@ internal sealed class AirAppMarketInstallService : IDisposable return new AirAppMarketInstallResult(false, null, combinedMessage); } - private bool IsPluginInstalled(string pluginId) + private bool IsAirAppInstalled(string pluginId) { return _runtime.Catalog.Any(entry => string.Equals(entry.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); } - private string? ValidateCompatibility(AirAppMarketPluginEntry plugin) => - AirAppMarketCompatibility.Validate(plugin, _hostVersion, PluginSdkInfo.ApiVersion); + private string? ValidateCompatibility(AirAppMarketAirAppEntry plugin) => + AirAppMarketCompatibility.Validate(plugin, _hostVersion, AirAppSdkInfo.ApiVersion); private async Task AcquirePackageAsync( - AirAppMarketPluginEntry plugin, - AirAppMarketPluginPackageSourceEntry source, + AirAppMarketAirAppEntry plugin, + AirAppMarketAirAppPackageSourceEntry source, string resolvedDownloadUrl, string attemptPath, CancellationToken cancellationToken) { if (AirAppMarketDefaults.TryResolveWorkspaceFile(resolvedDownloadUrl, out var localPackagePath)) { - if (source.SourceKind == PluginPackageSourceKind.WorkspaceLocal) + if (source.SourceKind == AirAppPackageSourceKind.WorkspaceLocal) { AppLogger.Info( - "PluginMarket", + "AirAppMarket", $"Copying workspace package for '{plugin.Id}' from '{localPackagePath}' to '{attemptPath}'."); } @@ -181,7 +181,7 @@ internal sealed class AirAppMarketInstallService : IDisposable return new AirAppMarketAcquisitionResult(true, null); } - if (source.SourceKind == PluginPackageSourceKind.WorkspaceLocal) + if (source.SourceKind == AirAppPackageSourceKind.WorkspaceLocal) { return new AirAppMarketAcquisitionResult( false, @@ -202,7 +202,7 @@ internal sealed class AirAppMarketInstallService : IDisposable } private async Task VerifyPackageAsync( - AirAppMarketPluginEntry plugin, + AirAppMarketAirAppEntry plugin, string attemptPath, CancellationToken cancellationToken) { @@ -217,8 +217,8 @@ internal sealed class AirAppMarketInstallService : IDisposable if (plugin.PackageSizeBytes > 0 && actualSize != plugin.PackageSizeBytes) { AppLogger.Error( - "PluginMarket", - $"Package verification failed. PluginId='{plugin.Id}'; Version='{plugin.Version}'; DownloadPath='{attemptPath}'; ExpectedSize='{plugin.PackageSizeBytes}'; ActualSize='{actualSize}'."); + "AirAppMarket", + $"Package verification failed. AirAppId='{plugin.Id}'; Version='{plugin.Version}'; DownloadPath='{attemptPath}'; ExpectedSize='{plugin.PackageSizeBytes}'; ActualSize='{actualSize}'."); return new AirAppMarketVerificationResult( false, $"Package verification failed. Expected size {plugin.PackageSizeBytes}, actual size {actualSize}."); @@ -228,8 +228,8 @@ internal sealed class AirAppMarketInstallService : IDisposable !string.Equals(actualHash, plugin.Sha256, StringComparison.OrdinalIgnoreCase)) { AppLogger.Error( - "PluginMarket", - $"Package hash verification failed. PluginId='{plugin.Id}'; Version='{plugin.Version}'; DownloadPath='{attemptPath}'; ExpectedHash='{plugin.Sha256}'; ActualHash='{actualHash}'."); + "AirAppMarket", + $"Package hash verification failed. AirAppId='{plugin.Id}'; Version='{plugin.Version}'; DownloadPath='{attemptPath}'; ExpectedHash='{plugin.Sha256}'; ActualHash='{actualHash}'."); return new AirAppMarketVerificationResult( false, $"Package verification failed. Expected SHA-256 {plugin.Sha256}, actual {actualHash}."); @@ -256,7 +256,7 @@ internal sealed class AirAppMarketInstallService : IDisposable private static string ResolveDownloadsDirectory(string dataDirectory) { var preferred = Path.Combine(dataDirectory, "downloads"); - if (PluginInstallTargetAccess.CanWriteDirectory(preferred)) + if (AirAppInstallTargetAccess.CanWriteDirectory(preferred)) { return preferred; } @@ -265,12 +265,12 @@ internal sealed class AirAppMarketInstallService : IDisposable var fallbackRoot = string.IsNullOrWhiteSpace(localAppData) ? Path.GetTempPath() : Path.Combine(localAppData, "LanMountainDesktop"); - return Path.Combine(fallbackRoot, "PluginMarket", "downloads"); + return Path.Combine(fallbackRoot, "AirAppMarket", "downloads"); } private async Task DownloadPackageAsync( - AirAppMarketPluginEntry plugin, - AirAppMarketPluginPackageSourceEntry source, + AirAppMarketAirAppEntry plugin, + AirAppMarketAirAppPackageSourceEntry source, CancellationToken cancellationToken) { var packagePath = Path.Combine( @@ -281,8 +281,8 @@ internal sealed class AirAppMarketInstallService : IDisposable { var resolvedDownloadUrl = await _releaseResolverService.ResolveDownloadUrlAsync(plugin, source, cancellationToken).ConfigureAwait(false); AppLogger.Info( - "PluginMarket", - $"Downloading package for deferred plugin install. PluginId='{plugin.Id}'; Source='{resolvedDownloadUrl}'."); + "AirAppMarket", + $"Downloading package for deferred plugin install. AirAppId='{plugin.Id}'; Source='{resolvedDownloadUrl}'."); var acquireResult = await AcquirePackageAsync(plugin, source, resolvedDownloadUrl, packagePath, cancellationToken).ConfigureAwait(false); if (!acquireResult.Success) @@ -312,25 +312,25 @@ internal sealed class AirAppMarketInstallService : IDisposable } } - private static PluginManifest ReadManifestFromPackage(string packagePath) + private static AirAppManifest ReadManifestFromPackage(string packagePath) { using var archive = System.IO.Compression.ZipFile.OpenRead(packagePath); var entries = archive.Entries - .Where(entry => string.Equals(entry.Name, "plugin.json", StringComparison.OrdinalIgnoreCase)) + .Where(entry => string.Equals(entry.Name, AirAppSdkInfo.ManifestFileName, StringComparison.OrdinalIgnoreCase)) .ToArray(); if (entries.Length == 0) { - throw new InvalidOperationException($"Plugin package '{packagePath}' does not contain 'plugin.json'."); + throw new InvalidOperationException($"AirApp package '{packagePath}' does not contain '{AirAppSdkInfo.ManifestFileName}'."); } if (entries.Length > 1) { - throw new InvalidOperationException($"Plugin package '{packagePath}' contains multiple 'plugin.json' files."); + throw new InvalidOperationException($"AirApp package '{packagePath}' contains multiple '{AirAppSdkInfo.ManifestFileName}' files."); } using var stream = entries[0].Open(); - return PluginManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); + return AirAppManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); } public void Dispose() @@ -361,7 +361,7 @@ internal sealed class AirAppMarketInstallService : IDisposable internal static class AirAppMarketCompatibility { public static string? Validate( - AirAppMarketPluginEntry plugin, + AirAppMarketAirAppEntry plugin, Version? hostVersion, string? hostApiVersion) { @@ -372,12 +372,12 @@ internal static class AirAppMarketCompatibility if (!AirAppMarketIndexDocument.TryParseVersion(plugin.MinHostVersion, out var minHostVersion) || minHostVersion is null) { - return $"Plugin '{plugin.Id}' declares invalid minimum host version '{plugin.MinHostVersion}'."; + return $"AirApp '{plugin.Id}' declares invalid minimum host version '{plugin.MinHostVersion}'."; } if (hostVersion < minHostVersion) { - return $"Plugin '{plugin.Id}' requires host version {plugin.MinHostVersion} or newer. Current host version is {hostVersion}."; + return $"AirApp '{plugin.Id}' requires host version {plugin.MinHostVersion} or newer. Current host version is {hostVersion}."; } } @@ -389,7 +389,7 @@ internal static class AirAppMarketCompatibility if (!AirAppMarketIndexDocument.TryParseVersion(plugin.ApiVersion, out var pluginApiVersion) || pluginApiVersion is null) { - return $"Plugin '{plugin.Id}' declares invalid API version '{plugin.ApiVersion}'."; + return $"AirApp '{plugin.Id}' declares invalid API version '{plugin.ApiVersion}'."; } if (string.IsNullOrWhiteSpace(hostApiVersion) || @@ -397,13 +397,13 @@ internal static class AirAppMarketCompatibility hostApiVersionParsed is null) { AppLogger.Warn( - "PluginMarket", + "AirAppMarket", $"Host API version '{hostApiVersion ?? string.Empty}' could not be parsed. Skipping API version check."); return null; } return pluginApiVersion.Major != hostApiVersionParsed.Major - ? $"Plugin '{plugin.Id}' uses incompatible API version {plugin.ApiVersion}. Host API version is {hostApiVersion}. Major version must match." + ? $"AirApp '{plugin.Id}' uses incompatible API version {plugin.ApiVersion}. Host API version is {hostApiVersion}. Major version must match." : null; } } diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketModels.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketModels.cs similarity index 91% rename from desktop/LanMountainDesktop/plugins/PluginMarketModels.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketModels.cs index 628e0c4..6ee1e85 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketModels.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketModels.cs @@ -4,11 +4,11 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text.Json; -using LanMountainDesktop.PluginSdk; -using static LanMountainDesktop.Services.PluginMarket.AirAppMarketDefaults; -using static LanMountainDesktop.Services.PluginMarket.AirAppMarketIndexDocument; +using LanMountainDesktop.AirAppSdk; +using static LanMountainDesktop.Services.AirAppMarket.AirAppMarketDefaults; +using static LanMountainDesktop.Services.AirAppMarket.AirAppMarketIndexDocument; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; /// /// Market index schema version. The host only understands this single self-contained flat format. @@ -220,9 +220,9 @@ internal static class AirAppMarketDefaults return !string.IsNullOrWhiteSpace(repositoryName) && !string.IsNullOrWhiteSpace(relativePath); } - public static bool TryParsePackageSourceKind(string? value, out PluginPackageSourceKind kind) + public static bool TryParsePackageSourceKind(string? value, out AirAppPackageSourceKind kind) { - kind = PluginPackageSourceKind.ReleaseAsset; + kind = AirAppPackageSourceKind.ReleaseAsset; var normalized = NormalizeValue(value); if (string.IsNullOrWhiteSpace(normalized)) { @@ -232,26 +232,26 @@ internal static class AirAppMarketDefaults switch (normalized) { case "releaseAsset": - kind = PluginPackageSourceKind.ReleaseAsset; + kind = AirAppPackageSourceKind.ReleaseAsset; return true; case "rawFallback": - kind = PluginPackageSourceKind.RawFallback; + kind = AirAppPackageSourceKind.RawFallback; return true; case "workspaceLocal": - kind = PluginPackageSourceKind.WorkspaceLocal; + kind = AirAppPackageSourceKind.WorkspaceLocal; return true; default: return false; } } - public static int GetPackageSourceOrder(PluginPackageSourceKind kind) + public static int GetPackageSourceOrder(AirAppPackageSourceKind kind) { return kind switch { - PluginPackageSourceKind.ReleaseAsset => 0, - PluginPackageSourceKind.RawFallback => 1, - PluginPackageSourceKind.WorkspaceLocal => 2, + AirAppPackageSourceKind.ReleaseAsset => 0, + AirAppPackageSourceKind.RawFallback => 1, + AirAppPackageSourceKind.WorkspaceLocal => 2, _ => int.MaxValue }; } @@ -307,7 +307,7 @@ internal sealed record AirAppMarketLoadResult( internal sealed record AirAppMarketInstallResult( bool Success, - PluginManifest? Manifest, + AirAppManifest? Manifest, string? ErrorMessage, bool RestartRequired = false); @@ -335,7 +335,8 @@ internal sealed class AirAppMarketIndexDocument public List Contracts { get; init; } = []; - public List Plugins { get; init; } = []; + [System.Text.Json.Serialization.JsonPropertyName("plugins")] + public List AirApps { get; init; } = []; public static AirAppMarketIndexDocument Load(string json, string sourceName) { @@ -378,18 +379,18 @@ internal sealed class AirAppMarketIndexDocument normalizedContracts.Add(normalizedContract); } - var normalizedPlugins = new List((Plugins ?? []).Count); + var normalizedAirApps = new List((AirApps ?? []).Count); var seenIds = new HashSet(StringComparer.OrdinalIgnoreCase); - foreach (var plugin in Plugins ?? []) + foreach (var plugin in AirApps ?? []) { - var normalizedPlugin = plugin.ValidateAndNormalize(sourceName); - if (!seenIds.Add(normalizedPlugin.Id)) + var normalizedAirApp = plugin.ValidateAndNormalize(sourceName); + if (!seenIds.Add(normalizedAirApp.Id)) { throw new InvalidOperationException( - $"Market index '{sourceName}' contains duplicate plugin id '{normalizedPlugin.Id}'."); + $"Market index '{sourceName}' contains duplicate plugin id '{normalizedAirApp.Id}'."); } - normalizedPlugins.Add(normalizedPlugin); + normalizedAirApps.Add(normalizedAirApp); } return new AirAppMarketIndexDocument @@ -404,7 +405,7 @@ internal sealed class AirAppMarketIndexDocument .OrderBy(contract => contract.Id, StringComparer.OrdinalIgnoreCase) .ThenBy(contract => contract.Version, StringComparer.OrdinalIgnoreCase) .ToList(), - Plugins = normalizedPlugins + AirApps = normalizedAirApps .OrderBy(plugin => plugin.Name, StringComparer.OrdinalIgnoreCase) .ToList() }; @@ -565,7 +566,7 @@ internal sealed class AirAppMarketSharedContractEntry } } -internal sealed class AirAppMarketPluginDependencyEntry +internal sealed class AirAppMarketAirAppDependencyEntry { public string Id { get; init; } = string.Empty; @@ -573,9 +574,9 @@ internal sealed class AirAppMarketPluginDependencyEntry public string AssemblyName { get; init; } = string.Empty; - public AirAppMarketPluginDependencyEntry ValidateAndNormalize(string sourceName) + public AirAppMarketAirAppDependencyEntry ValidateAndNormalize(string sourceName) { - return new AirAppMarketPluginDependencyEntry + return new AirAppMarketAirAppDependencyEntry { Id = NormalizeValue(Id) ?? throw new InvalidOperationException( @@ -588,15 +589,15 @@ internal sealed class AirAppMarketPluginDependencyEntry } } -internal sealed class AirAppMarketPluginPackageSourceEntry +internal sealed class AirAppMarketAirAppPackageSourceEntry { public string Kind { get; init; } = string.Empty; public string Url { get; init; } = string.Empty; - public PluginPackageSourceKind SourceKind { get; init; } = PluginPackageSourceKind.ReleaseAsset; + public AirAppPackageSourceKind SourceKind { get; init; } = AirAppPackageSourceKind.ReleaseAsset; - public AirAppMarketPluginPackageSourceEntry ValidateAndNormalize(string sourceName, string pluginId) + public AirAppMarketAirAppPackageSourceEntry ValidateAndNormalize(string sourceName, string pluginId) { var normalizedKind = NormalizeValue(Kind) ?? throw new InvalidOperationException( @@ -612,13 +613,13 @@ internal sealed class AirAppMarketPluginPackageSourceEntry $"Market index '{sourceName}' is missing package source url for plugin '{pluginId}'."); EnsurePackageSourceUrl(normalizedUrl, sourceName, pluginId); - return new AirAppMarketPluginPackageSourceEntry + return new AirAppMarketAirAppPackageSourceEntry { Kind = sourceKind switch { - PluginPackageSourceKind.ReleaseAsset => "releaseAsset", - PluginPackageSourceKind.RawFallback => "rawFallback", - PluginPackageSourceKind.WorkspaceLocal => "workspaceLocal", + AirAppPackageSourceKind.ReleaseAsset => "releaseAsset", + AirAppPackageSourceKind.RawFallback => "rawFallback", + AirAppPackageSourceKind.WorkspaceLocal => "workspaceLocal", _ => normalizedKind }, Url = normalizedUrl, @@ -652,9 +653,10 @@ internal sealed class AirAppMarketPluginPackageSourceEntry /// All display and acquisition metadata lives directly on this object; there are no /// nested manifest/compatibility/repository/publication fallback objects. /// -internal sealed class AirAppMarketPluginEntry +internal sealed class AirAppMarketAirAppEntry { - public string PluginId { get; init; } = string.Empty; + [System.Text.Json.Serialization.JsonPropertyName("pluginId")] + public string AirAppId { get; init; } = string.Empty; public string Id { get; init; } = string.Empty; @@ -700,9 +702,9 @@ internal sealed class AirAppMarketPluginEntry public List Tags { get; init; } = []; - public List SharedContracts { get; init; } = []; + public List SharedContracts { get; init; } = []; - public List PackageSources { get; init; } = []; + public List PackageSources { get; init; } = []; public List DesktopComponents { get; init; } = []; @@ -720,9 +722,9 @@ internal sealed class AirAppMarketPluginEntry !string.IsNullOrWhiteSpace(ReleaseTag) && !string.IsNullOrWhiteSpace(ReleaseAssetName); - public AirAppMarketPluginEntry ValidateAndNormalize(string sourceName) + public AirAppMarketAirAppEntry ValidateAndNormalize(string sourceName) { - var resolvedId = NormalizeValue(PluginId) ?? NormalizeValue(Id) + var resolvedId = NormalizeValue(AirAppId) ?? NormalizeValue(Id) ?? throw new InvalidOperationException($"Market index '{sourceName}' is missing plugin id."); var resolvedName = NormalizeValue(Name) @@ -794,9 +796,9 @@ internal sealed class AirAppMarketPluginEntry $"Market index '{sourceName}' is missing package sources for plugin '{resolvedId}'."); } - return new AirAppMarketPluginEntry + return new AirAppMarketAirAppEntry { - PluginId = resolvedId, + AirAppId = resolvedId, Id = resolvedId, Name = resolvedName, Description = resolvedDescription, @@ -838,20 +840,20 @@ internal sealed class AirAppMarketPluginEntry string.IsNullOrWhiteSpace(MinHostVersion) ? "?" : MinHostVersion); } - public IReadOnlyList GetPackageSourcesInInstallOrder() + public IReadOnlyList GetPackageSourcesInInstallOrder() { return PackageSources .OrderBy(source => AirAppMarketDefaults.GetPackageSourceOrder(source.SourceKind)) .ToList(); } - private static List NormalizePackageSources( - IReadOnlyList? packageSources, + private static List NormalizePackageSources( + IReadOnlyList? packageSources, string sourceName, string pluginId) { - var normalizedSources = new List((packageSources ?? []).Count); - var seenKinds = new HashSet(); + var normalizedSources = new List((packageSources ?? []).Count); + var seenKinds = new HashSet(); var previousOrder = -1; foreach (var source in packageSources ?? []) { @@ -876,12 +878,12 @@ internal sealed class AirAppMarketPluginEntry return normalizedSources; } - private static List NormalizeDependencies( - IReadOnlyList? dependencies, + private static List NormalizeDependencies( + IReadOnlyList? dependencies, string sourceName, string pluginId) { - var normalizedDependencies = new List((dependencies ?? []).Count); + var normalizedDependencies = new List((dependencies ?? []).Count); var seenDependencies = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var dependency in dependencies ?? []) { diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketReadmeService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketReadmeService.cs similarity index 91% rename from desktop/LanMountainDesktop/plugins/PluginMarketReadmeService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketReadmeService.cs index c0d3e54..1228801 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketReadmeService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketReadmeService.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using LanMountainDesktop.Services.Settings; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; /// /// Loads plugin README markdown from the local workspace, the on-disk asset cache, or the network, @@ -13,7 +13,7 @@ namespace LanMountainDesktop.Services.PluginMarket; /// public sealed class AirAppMarketReadmeService : IDisposable { - private readonly PluginMarketAssetCacheService? _cache; + private readonly AirAppMarketAssetCacheService? _cache; private readonly HttpClient _httpClient; public AirAppMarketReadmeService() @@ -21,18 +21,18 @@ public sealed class AirAppMarketReadmeService : IDisposable { } - public AirAppMarketReadmeService(PluginMarketAssetCacheService? cache) + public AirAppMarketReadmeService(AirAppMarketAssetCacheService? cache) { _cache = cache; _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(20) }; - _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0"); + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-AirAppMarketplace/1.0"); } public async Task LoadAsync( - PluginCatalogItemInfo plugin, + AirAppCatalogItemInfo plugin, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(plugin); diff --git a/desktop/LanMountainDesktop/plugins/PluginMarketReleaseResolverService.cs b/desktop/LanMountainDesktop/AirApps/AirAppMarketReleaseResolverService.cs similarity index 85% rename from desktop/LanMountainDesktop/plugins/PluginMarketReleaseResolverService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppMarketReleaseResolverService.cs index 19a4fcb..1db0285 100644 --- a/desktop/LanMountainDesktop/plugins/PluginMarketReleaseResolverService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppMarketReleaseResolverService.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using LanMountainDesktop.Services; -namespace LanMountainDesktop.Services.PluginMarket; +namespace LanMountainDesktop.Services.AirAppMarket; internal sealed class AirAppMarketReleaseResolverService { @@ -17,7 +17,7 @@ internal sealed class AirAppMarketReleaseResolverService } public async Task ResolveDownloadUrlAsync( - AirAppMarketPluginEntry plugin, + AirAppMarketAirAppEntry plugin, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(plugin); @@ -32,8 +32,8 @@ internal sealed class AirAppMarketReleaseResolverService } public async Task ResolveDownloadUrlAsync( - AirAppMarketPluginEntry plugin, - AirAppMarketPluginPackageSourceEntry source, + AirAppMarketAirAppEntry plugin, + AirAppMarketAirAppPackageSourceEntry source, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(plugin); @@ -41,16 +41,16 @@ internal sealed class AirAppMarketReleaseResolverService return source.SourceKind switch { - PluginPackageSourceKind.ReleaseAsset => await ResolveReleaseAssetDownloadUrlAsync(plugin, source, cancellationToken).ConfigureAwait(false), - PluginPackageSourceKind.RawFallback => source.Url, - PluginPackageSourceKind.WorkspaceLocal => source.Url, + AirAppPackageSourceKind.ReleaseAsset => await ResolveReleaseAssetDownloadUrlAsync(plugin, source, cancellationToken).ConfigureAwait(false), + AirAppPackageSourceKind.RawFallback => source.Url, + AirAppPackageSourceKind.WorkspaceLocal => source.Url, _ => source.Url }; } private async Task ResolveReleaseAssetDownloadUrlAsync( - AirAppMarketPluginEntry plugin, - AirAppMarketPluginPackageSourceEntry source, + AirAppMarketAirAppEntry plugin, + AirAppMarketAirAppPackageSourceEntry source, CancellationToken cancellationToken) { var sourceUrl = source.Url; @@ -91,7 +91,7 @@ internal sealed class AirAppMarketReleaseResolverService } private static bool TryGetRepositoryIdentity( - AirAppMarketPluginEntry plugin, + AirAppMarketAirAppEntry plugin, out string owner, out string repositoryName) { diff --git a/desktop/LanMountainDesktop/plugins/PluginRuntimeService.cs b/desktop/LanMountainDesktop/AirApps/AirAppRuntimeService.cs similarity index 63% rename from desktop/LanMountainDesktop/plugins/PluginRuntimeService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppRuntimeService.cs index baa8d1f..649f23f 100644 --- a/desktop/LanMountainDesktop/plugins/PluginRuntimeService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppRuntimeService.cs @@ -10,8 +10,8 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; using LanMountainDesktop.Models; -using LanMountainDesktop.Plugins; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirApps; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Shared.IPC; using Microsoft.Extensions.DependencyInjection; @@ -19,38 +19,38 @@ using Microsoft.Extensions.Hosting; namespace LanMountainDesktop.Services; -public sealed class PluginRuntimeService : IDisposable +public sealed class AirAppRuntimeService : IDisposable { private const string PendingDeletionFileName = ".pending-plugin-deletions.json"; - private readonly PluginLoaderOptions _loaderOptions; - private readonly PluginLoader _loader; + private readonly AirAppLoaderOptions _loaderOptions; + private readonly AirAppLoader _loader; private readonly IHostApplicationLifecycle _applicationLifecycle = new HostApplicationLifecycleService(); - private readonly PluginExportRegistry _exportRegistry = new(); - private readonly PluginSharedContractManager _sharedContractManager; + private readonly AirAppExportRegistry _exportRegistry = new(); + private readonly AirAppSharedContractManager _sharedContractManager; private readonly IServiceProvider _hostServices; - private readonly IPluginPackageManager _packageManager; + private readonly IAirAppPackageManager _packageManager; private readonly ISettingsFacadeService _settingsFacade; private readonly SettingsCatalogService _settingsCatalogService; private readonly PublicIpcHostService? _publicIpcHostService; private readonly IMaterialColorService _materialColorService; - private readonly List _loadedPlugins = []; - private readonly List _loadResults = []; - private readonly List _catalog = []; - private readonly List _settingsSections = []; - private readonly List _desktopComponents = []; - private readonly List _desktopComponentEditors = []; + private readonly List _loadedAirApps = []; + private readonly List _loadResults = []; + private readonly List _catalog = []; + private readonly List _settingsSections = []; + private readonly List _desktopComponents = []; + private readonly List _desktopComponentEditors = []; private readonly object _packageMutationGate = new(); - public PluginRuntimeService( + public AirAppRuntimeService( ISettingsFacadeService? settingsFacade = null, PublicIpcHostService? publicIpcHostService = null) { var dataRoot = AppDataPathProvider.GetDataRoot(); - PluginsDirectory = Path.Combine(dataRoot, "Extensions", "Plugins"); - _sharedContractManager = new PluginSharedContractManager( - AppDataPathProvider.GetPluginMarketDirectory()); - _packageManager = new PluginRuntimePackageManager(this); + AirAppsDirectory = Path.Combine(dataRoot, "Extensions", "AirApps"); + _sharedContractManager = new AirAppSharedContractManager( + AppDataPathProvider.GetAirAppMarketDirectory()); + _packageManager = new AirAppRuntimePackageManager(this); _settingsFacade = settingsFacade ?? new SettingsFacadeService(); _publicIpcHostService = publicIpcHostService; _materialColorService = HostMaterialColorProvider.GetOrCreate(); @@ -58,9 +58,9 @@ public sealed class PluginRuntimeService : IDisposable ?? new SettingsCatalogService(); if (_settingsFacade is SettingsFacadeService concreteFacade) { - concreteFacade.BindPluginRuntime(this); + concreteFacade.BindAirAppRuntime(this); } - _hostServices = new PluginHostServiceProvider( + _hostServices = new AirAppHostServiceProvider( _packageManager, _applicationLifecycle, _exportRegistry, @@ -69,87 +69,87 @@ public sealed class PluginRuntimeService : IDisposable _settingsFacade.Catalog, _publicIpcHostService); _loaderOptions = CreateOptions(); - _loader = new PluginLoader(_loaderOptions); + _loader = new AirAppLoader(_loaderOptions); _materialColorService.MaterialColorChanged += OnMaterialColorChanged; } - public string PluginsDirectory { get; } + public string AirAppsDirectory { get; } - public IReadOnlyList LoadedPlugins => _loadedPlugins; + public IReadOnlyList LoadedAirApps => _loadedAirApps; - public IReadOnlyList LoadResults => _loadResults; + public IReadOnlyList LoadResults => _loadResults; - public IReadOnlyList Catalog => _catalog; + public IReadOnlyList Catalog => _catalog; - public IReadOnlyList SettingsSections => _settingsSections; + public IReadOnlyList SettingsSections => _settingsSections; - public IReadOnlyList DesktopComponents => _desktopComponents; - public IReadOnlyList DesktopComponentEditors => _desktopComponentEditors; + public IReadOnlyList DesktopComponents => _desktopComponents; + public IReadOnlyList DesktopComponentEditors => _desktopComponentEditors; - public IPluginExportRegistry ExportRegistry => _exportRegistry; + public IAirAppExportRegistry ExportRegistry => _exportRegistry; public ISettingsFacadeService SettingsFacade => _settingsFacade; - public void LoadInstalledPlugins() + public void LoadInstalledAirApps() { - Directory.CreateDirectory(PluginsDirectory); - UnloadInstalledPlugins(); - ApplyPendingPluginDeletions(); + Directory.CreateDirectory(AirAppsDirectory); + UnloadInstalledAirApps(); + ApplyPendingAirAppDeletions(); ApplyPendingPluginOperations(); MergeDevSettingsFromSnapshot(); - AppLogger.Info("PluginRuntime", $"Loading installed plugins from '{PluginsDirectory}'."); + AppLogger.Info("AirAppRuntime", $"Loading installed plugins from '{AirAppsDirectory}'."); - var disabledPluginIds = GetDisabledPluginIds(); + var disabledAirAppIds = GetDisabledPluginIds(); var settingsSnapshot = LoadAppSettingsSnapshot(); - var hostLanguageCode = PluginLocalizer.NormalizeLanguageCode(settingsSnapshot.LanguageCode); + var hostLanguageCode = AirAppLocalizer.NormalizeLanguageCode(settingsSnapshot.LanguageCode); var hostProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) { - [PluginHostPropertyKeys.HostApplicationName] = "LanMountainDesktop", - [PluginHostPropertyKeys.HostVersion] = typeof(App).Assembly.GetName().Version?.ToString(), - [PluginHostPropertyKeys.PluginSdkApiVersion] = PluginSdkInfo.ApiVersion, - [PluginHostPropertyKeys.HostLanguageCode] = hostLanguageCode + [AirAppHostPropertyKeys.HostApplicationName] = "LanMountainDesktop", + [AirAppHostPropertyKeys.HostVersion] = typeof(App).Assembly.GetName().Version?.ToString(), + [AirAppHostPropertyKeys.AirAppSdkApiVersion] = AirAppSdkInfo.ApiVersion, + [AirAppHostPropertyKeys.HostLanguageCode] = hostLanguageCode }; - var discoveryFailures = new List(); + var discoveryFailures = new List(); var candidates = DiscoverCandidates(discoveryFailures); _loadResults.AddRange(discoveryFailures); AppLogger.Info( - "PluginRuntime", - $"Plugin discovery completed. Candidates={candidates.Count}; DiscoveryFailures={discoveryFailures.Count}; PluginsDirectory='{PluginsDirectory}'."); + "AirAppRuntime", + $"AirApp discovery completed. Candidates={candidates.Count}; DiscoveryFailures={discoveryFailures.Count}; AirAppsDirectory='{AirAppsDirectory}'."); - var selectedPluginIds = new HashSet(StringComparer.OrdinalIgnoreCase); + var selectedAirAppIds = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var candidate in candidates) { - var isDevPlugin = candidate.SourceKind == PluginCatalogSourceKind.DevPlugin; + var isDevAirApp = candidate.SourceKind == AirAppCatalogSourceKind.DevAirApp; - if (!selectedPluginIds.Add(candidate.Manifest.Id)) + if (!selectedAirAppIds.Add(candidate.Manifest.Id)) { - if (isDevPlugin) + if (isDevAirApp) { AppLogger.Info( - "DevPlugin", + "DevAirApp", $"Developer plugin '{candidate.Manifest.Id}' overrides an already-registered plugin from '{candidate.SourcePath}'."); } else { - var duplicateFailure = PluginLoadResult.Failure( + var duplicateFailure = AirAppLoadResult.Failure( candidate.SourcePath, candidate.Manifest, new InvalidOperationException( $"Duplicate plugin id '{candidate.Manifest.Id}' was found. Source '{candidate.SourcePath}' was ignored because a higher-priority source was already selected.")); _loadResults.Add(duplicateFailure); - LogPluginFailure("CatalogSelection", duplicateFailure, treatAsError: false); + LogAirAppFailure("CatalogSelection", duplicateFailure, treatAsError: false); continue; } } - var isEnabled = isDevPlugin || !disabledPluginIds.Contains(candidate.Manifest.Id); + var isEnabled = isDevAirApp || !disabledAirAppIds.Contains(candidate.Manifest.Id); if (!isEnabled) { - _catalog.Add(new PluginCatalogEntry( + _catalog.Add(new AirAppCatalogEntry( candidate.Manifest, candidate.SourcePath, - candidate.SourceKind == PluginCatalogSourceKind.Package, + candidate.SourceKind == AirAppCatalogSourceKind.Package, false, false, null, @@ -161,41 +161,41 @@ public sealed class PluginRuntimeService : IDisposable try { AppLogger.Info( - "PluginRuntime", - $"Preparing shared contracts. PluginId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'; SourceKind='{candidate.SourceKind}'."); + "AirAppRuntime", + $"Preparing shared contracts. AirAppId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'; SourceKind='{candidate.SourceKind}'."); RegisterSharedContractsForLoad(candidate.Manifest); AppLogger.Info( - "PluginRuntime", - $"Shared contracts ready. PluginId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'."); + "AirAppRuntime", + $"Shared contracts ready. AirAppId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'."); } catch (Exception ex) { - var dependencyFailure = PluginLoadResult.Failure(candidate.SourcePath, candidate.Manifest, ex); + var dependencyFailure = AirAppLoadResult.Failure(candidate.SourcePath, candidate.Manifest, ex); _loadResults.Add(dependencyFailure); - _catalog.Add(new PluginCatalogEntry( + _catalog.Add(new AirAppCatalogEntry( candidate.Manifest, candidate.SourcePath, - candidate.SourceKind == PluginCatalogSourceKind.Package, + candidate.SourceKind == AirAppCatalogSourceKind.Package, true, false, ex.Message, 0, 0)); - LogPluginFailure("DependencyPrepare", dependencyFailure, treatAsError: false); + LogAirAppFailure("DependencyPrepare", dependencyFailure, treatAsError: false); continue; } AppLogger.Info( - "PluginRuntime", - $"Starting plugin load. PluginId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'; SourceKind='{candidate.SourceKind}'."); + "AirAppRuntime", + $"Starting plugin load. AirAppId='{candidate.Manifest.Id}'; SourcePath='{candidate.SourcePath}'; SourceKind='{candidate.SourceKind}'."); var loadResult = candidate.SourceKind switch { - PluginCatalogSourceKind.Package => _loader.LoadFromPackage( + AirAppCatalogSourceKind.Package => _loader.LoadFromPackage( candidate.SourcePath, - PluginsDirectory, + AirAppsDirectory, services: _hostServices, hostProperties), - PluginCatalogSourceKind.DevPlugin => _loader.LoadFromManifest( + AirAppCatalogSourceKind.DevAirApp => _loader.LoadFromManifest( candidate.SourcePath, services: _hostServices, hostProperties), @@ -207,51 +207,51 @@ public sealed class PluginRuntimeService : IDisposable _loadResults.Add(loadResult); - if (loadResult.IsSuccess && loadResult.LoadedPlugin is not null) + if (loadResult.IsSuccess && loadResult.LoadedAirApp is not null) { - _loadedPlugins.Add(loadResult.LoadedPlugin); - CollectContributions(loadResult.LoadedPlugin); - _catalog.Add(new PluginCatalogEntry( - loadResult.LoadedPlugin.Manifest, + _loadedAirApps.Add(loadResult.LoadedAirApp); + CollectContributions(loadResult.LoadedAirApp); + _catalog.Add(new AirAppCatalogEntry( + loadResult.LoadedAirApp.Manifest, loadResult.SourcePath, - candidate.SourceKind == PluginCatalogSourceKind.Package, + candidate.SourceKind == AirAppCatalogSourceKind.Package, true, true, null, - loadResult.LoadedPlugin.SettingsSections.Count, - loadResult.LoadedPlugin.DesktopComponents.Count, - IsDevPlugin: isDevPlugin)); + loadResult.LoadedAirApp.SettingsSections.Count, + loadResult.LoadedAirApp.DesktopComponents.Count, + IsDevAirApp: isDevAirApp)); AppLogger.Info( - "PluginRuntime", - $"Plugin loaded. PluginId='{loadResult.LoadedPlugin.Manifest.Id}'; SourcePath='{loadResult.SourcePath}'; ManifestVersion='{loadResult.LoadedPlugin.Manifest.Version ?? ""}'; ApiVersion='{loadResult.LoadedPlugin.Manifest.ApiVersion ?? ""}'; SourceKind='{candidate.SourceKind}'; SettingsSections={loadResult.LoadedPlugin.SettingsSections.Count}; Widgets={loadResult.LoadedPlugin.DesktopComponents.Count}; Editors={loadResult.LoadedPlugin.DesktopComponentEditors.Count}."); - Debug.WriteLine($"[PluginRuntime] Loaded '{loadResult.Manifest?.Id}' from '{loadResult.SourcePath}'."); + "AirAppRuntime", + $"AirApp loaded. AirAppId='{loadResult.LoadedAirApp.Manifest.Id}'; SourcePath='{loadResult.SourcePath}'; ManifestVersion='{loadResult.LoadedAirApp.Manifest.Version ?? ""}'; ApiVersion='{loadResult.LoadedAirApp.Manifest.ApiVersion ?? ""}'; SourceKind='{candidate.SourceKind}'; SettingsSections={loadResult.LoadedAirApp.SettingsSections.Count}; Widgets={loadResult.LoadedAirApp.DesktopComponents.Count}; Editors={loadResult.LoadedAirApp.DesktopComponentEditors.Count}."); + Debug.WriteLine($"[AirAppRuntime] Loaded '{loadResult.Manifest?.Id}' from '{loadResult.SourcePath}'."); continue; } - _catalog.Add(new PluginCatalogEntry( + _catalog.Add(new AirAppCatalogEntry( candidate.Manifest, candidate.SourcePath, - candidate.SourceKind == PluginCatalogSourceKind.Package, + candidate.SourceKind == AirAppCatalogSourceKind.Package, true, false, loadResult.Error?.Message, 0, 0, - IsDevPlugin: isDevPlugin)); - LogPluginFailure("Load", loadResult, treatAsError: true); - Debug.WriteLine($"[PluginRuntime] Failed to load plugin from '{loadResult.SourcePath}': {loadResult.Error}"); + IsDevAirApp: isDevAirApp)); + LogAirAppFailure("Load", loadResult, treatAsError: true); + Debug.WriteLine($"[AirAppRuntime] Failed to load plugin from '{loadResult.SourcePath}': {loadResult.Error}"); } if (_catalog.Count == 0 && discoveryFailures.Count == 0) { AppLogger.Info( - "PluginRuntime", - $"No plugin packages or loose manifests were discovered under '{PluginsDirectory}'."); - Debug.WriteLine($"[PluginRuntime] No .laapp packages or loose plugin manifests found under '{PluginsDirectory}'."); + "AirAppRuntime", + $"No plugin packages or loose manifests were discovered under '{AirAppsDirectory}'."); + Debug.WriteLine($"[AirAppRuntime] No .laapp packages or loose plugin manifests found under '{AirAppsDirectory}'."); } } - public bool SetPluginEnabled(string pluginId, bool isEnabled) + public bool SetAirAppEnabled(string pluginId, bool isEnabled) { if (string.IsNullOrWhiteSpace(pluginId)) { @@ -260,31 +260,31 @@ public sealed class PluginRuntimeService : IDisposable var catalogEntry = _catalog.FirstOrDefault(entry => string.Equals(entry.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); - if (catalogEntry.IsDevPlugin && !isEnabled) + if (catalogEntry.IsDevAirApp && !isEnabled) { - AppLogger.Warn("DevPlugin", $"Cannot disable developer plugin '{pluginId}'. Developer plugins are always enabled in dev mode."); + AppLogger.Warn("DevAirApp", $"Cannot disable developer plugin '{pluginId}'. Developer plugins are always enabled in dev mode."); return false; } var snapshot = LoadAppSettingsSnapshot(); - var disabledPluginIds = snapshot.DisabledPluginIds is { Count: > 0 } + var disabledAirAppIds = snapshot.DisabledPluginIds is { Count: > 0 } ? new HashSet(snapshot.DisabledPluginIds, StringComparer.OrdinalIgnoreCase) : new HashSet(StringComparer.OrdinalIgnoreCase); var changed = isEnabled - ? disabledPluginIds.Remove(pluginId) - : disabledPluginIds.Add(pluginId); + ? disabledAirAppIds.Remove(pluginId) + : disabledAirAppIds.Add(pluginId); if (!changed) { return false; } - snapshot.DisabledPluginIds = disabledPluginIds + snapshot.DisabledPluginIds = disabledAirAppIds .OrderBy(id => id, StringComparer.OrdinalIgnoreCase) .ToList(); SaveAppSettingsSnapshot(snapshot); - PendingRestartStateService.SetPending(PendingRestartStateService.PluginCatalogReason, true); + PendingRestartStateService.SetPending(PendingRestartStateService.AirAppCatalogReason, true); for (var i = 0; i < _catalog.Count; i++) { @@ -297,31 +297,31 @@ public sealed class PluginRuntimeService : IDisposable return true; } - public PluginManifest InstallPluginPackage(string packagePath) + public AirAppManifest InstallAirAppPackage(string packagePath) { lock (_packageMutationGate) { - return InstallPluginPackageCore(packagePath).Manifest; + return InstallAirAppPackageCore(packagePath).Manifest; } } - public PluginManifest RegisterInstalledPluginPackage(string packagePath) + public AirAppManifest RegisterInstalledAirAppPackage(string packagePath) { lock (_packageMutationGate) { - return RegisterInstalledPluginPackageCore(packagePath); + return RegisterInstalledAirAppPackageCore(packagePath); } } - public bool DeleteInstalledPlugin(string pluginId) + public bool DeleteInstalledAirApp(string pluginId) { lock (_packageMutationGate) { - return DeleteInstalledPluginCore(pluginId); + return DeleteInstalledAirAppCore(pluginId); } } - private bool DeleteInstalledPluginCore(string pluginId) + private bool DeleteInstalledAirAppCore(string pluginId) { if (string.IsNullOrWhiteSpace(pluginId)) { @@ -335,29 +335,29 @@ public sealed class PluginRuntimeService : IDisposable return false; } - var targetPath = ResolvePluginRemovalTargetPath(entry); + var targetPath = ResolveAirAppRemovalTargetPath(entry); if (string.IsNullOrWhiteSpace(targetPath)) { return false; } var fullTargetPath = Path.GetFullPath(targetPath); - if (!TryDeletePluginTarget(fullTargetPath)) + if (!TryDeleteAirAppTarget(fullTargetPath)) { - RegisterPendingPluginDeletion(fullTargetPath); + RegisterPendingAirAppDeletion(fullTargetPath); } - RemovePluginFromSnapshot(pluginId); - RemovePluginFromCatalog(pluginId); - PendingRestartStateService.SetPending(PendingRestartStateService.PluginCatalogReason, true); + RemoveAirAppFromSnapshot(pluginId); + RemoveAirAppFromCatalog(pluginId); + PendingRestartStateService.SetPending(PendingRestartStateService.AirAppCatalogReason, true); return true; } - internal IReadOnlyList GetInstalledPluginsSnapshot() + internal IReadOnlyList GetInstalledAirAppsSnapshot() { return _catalog .OrderBy(entry => entry.Manifest.Name, StringComparer.OrdinalIgnoreCase) - .Select(entry => new InstalledPluginInfo( + .Select(entry => new AirAppInstalledInfo( entry.Manifest, entry.IsEnabled, entry.IsLoaded, @@ -366,65 +366,65 @@ public sealed class PluginRuntimeService : IDisposable .ToArray(); } - private PluginPackageInstallResult InstallPluginPackageCore(string packagePath) + private AirAppPackageInstallResult InstallAirAppPackageCore(string packagePath) { ArgumentException.ThrowIfNullOrWhiteSpace(packagePath); var fullPackagePath = Path.GetFullPath(packagePath); if (!File.Exists(fullPackagePath)) { - throw new FileNotFoundException($"Plugin package '{fullPackagePath}' was not found.", fullPackagePath); + throw new FileNotFoundException($"AirApp package '{fullPackagePath}' was not found.", fullPackagePath); } - if (!string.Equals(Path.GetExtension(fullPackagePath), PluginSdkInfo.PackageFileExtension, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(Path.GetExtension(fullPackagePath), AirAppSdkInfo.PackageFileExtension, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException( - $"Plugin package must use the '{PluginSdkInfo.PackageFileExtension}' extension."); + $"AirApp package must use the '{AirAppSdkInfo.PackageFileExtension}' extension."); } - Directory.CreateDirectory(PluginsDirectory); + Directory.CreateDirectory(AirAppsDirectory); var manifest = ReadManifestFromPackage(fullPackagePath); _sharedContractManager.EnsureInstalled(manifest); AppLogger.Info( - "PluginRuntime", - $"Installing package. PluginId='{manifest.Id}'; Source='{fullPackagePath}'; PluginsDirectory='{PluginsDirectory}'."); + "AirAppRuntime", + $"Installing package. AirAppId='{manifest.Id}'; Source='{fullPackagePath}'; AirAppsDirectory='{AirAppsDirectory}'."); - var destinationPath = Path.Combine(PluginsDirectory, BuildInstalledPackageFileName(manifest.Id)); - if (!PluginInstallTargetAccess.CanWriteDirectory(PluginsDirectory)) + var destinationPath = Path.Combine(AirAppsDirectory, BuildInstalledPackageFileName(manifest.Id)); + if (!AirAppInstallTargetAccess.CanWriteDirectory(AirAppsDirectory)) { - return InstallPluginPackageWithElevation(fullPackagePath, manifest, destinationPath); + return InstallAirAppPackageWithElevation(fullPackagePath, manifest, destinationPath); } - var replacedExisting = RemoveExistingPluginPackages(manifest.Id, fullPackagePath); + var replacedExisting = RemoveExistingAirAppPackages(manifest.Id, fullPackagePath); if (!string.Equals(fullPackagePath, Path.GetFullPath(destinationPath), StringComparison.OrdinalIgnoreCase)) { - FileOperationRetryHelper.CopyWithRetry(fullPackagePath, destinationPath, overwrite: true, "PluginRuntime"); + FileOperationRetryHelper.CopyWithRetry(fullPackagePath, destinationPath, overwrite: true, "AirAppRuntime"); } UpdateCatalogAfterPackageInstall(manifest, destinationPath); - PendingRestartStateService.SetPending(PendingRestartStateService.PluginCatalogReason, true); + PendingRestartStateService.SetPending(PendingRestartStateService.AirAppCatalogReason, true); AppLogger.Info( - "PluginRuntime", - $"Package staged. PluginId='{manifest.Id}'; Destination='{destinationPath}'; ReplacedExisting={replacedExisting}."); + "AirAppRuntime", + $"Package staged. AirAppId='{manifest.Id}'; Destination='{destinationPath}'; ReplacedExisting={replacedExisting}."); - return new PluginPackageInstallResult(manifest, replacedExisting, RestartRequired: true); + return new AirAppPackageInstallResult(manifest, replacedExisting, RestartRequired: true); } - private PluginPackageInstallResult InstallPluginPackageWithElevation( + private AirAppPackageInstallResult InstallAirAppPackageWithElevation( string fullPackagePath, - PluginManifest manifest, + AirAppManifest manifest, string destinationPath) { if (!OperatingSystem.IsWindows()) { throw new UnauthorizedAccessException( - $"Plugin directory '{PluginsDirectory}' is not writable by the current process."); + $"AirApp directory '{AirAppsDirectory}' is not writable by the current process."); } - var elevatedResult = new ElevatedPluginInstallService() - .InstallAsync(fullPackagePath, PluginsDirectory, CancellationToken.None) + var elevatedResult = new ElevatedAirAppInstallService() + .InstallAsync(fullPackagePath, AirAppsDirectory, CancellationToken.None) .GetAwaiter() .GetResult(); if (!elevatedResult.Success) @@ -439,38 +439,38 @@ public sealed class PluginRuntimeService : IDisposable ? elevatedResult.InstalledPackagePath : destinationPath; UpdateCatalogAfterPackageInstall(manifest, installedPath); - PendingRestartStateService.SetPending(PendingRestartStateService.PluginCatalogReason, true); + PendingRestartStateService.SetPending(PendingRestartStateService.AirAppCatalogReason, true); AppLogger.Info( - "PluginRuntime", - $"Package staged through elevated installer. PluginId='{manifest.Id}'; Destination='{installedPath}'."); + "AirAppRuntime", + $"Package staged through elevated installer. AirAppId='{manifest.Id}'; Destination='{installedPath}'."); - return new PluginPackageInstallResult(manifest, ReplacedExisting: false, RestartRequired: true); + return new AirAppPackageInstallResult(manifest, ReplacedExisting: false, RestartRequired: true); } - private PluginManifest RegisterInstalledPluginPackageCore(string packagePath) + private AirAppManifest RegisterInstalledAirAppPackageCore(string packagePath) { ArgumentException.ThrowIfNullOrWhiteSpace(packagePath); var fullPackagePath = Path.GetFullPath(packagePath); if (!File.Exists(fullPackagePath)) { - throw new FileNotFoundException($"Plugin package '{fullPackagePath}' was not found.", fullPackagePath); + throw new FileNotFoundException($"AirApp package '{fullPackagePath}' was not found.", fullPackagePath); } var manifest = ReadManifestFromPackage(fullPackagePath); _sharedContractManager.EnsureInstalled(manifest); AppLogger.Info( - "PluginRuntime", - $"Registering externally installed package. PluginId='{manifest.Id}'; Source='{fullPackagePath}'."); + "AirAppRuntime", + $"Registering externally installed package. AirAppId='{manifest.Id}'; Source='{fullPackagePath}'."); UpdateCatalogAfterPackageInstall(manifest, fullPackagePath); - PendingRestartStateService.SetPending(PendingRestartStateService.PluginCatalogReason, true); + PendingRestartStateService.SetPending(PendingRestartStateService.AirAppCatalogReason, true); return manifest; } public void Dispose() { _materialColorService.MaterialColorChanged -= OnMaterialColorChanged; - UnloadInstalledPlugins(); + UnloadInstalledAirApps(); _sharedContractManager.Dispose(); if (_settingsFacade is IDisposable disposable && !ReferenceEquals(_settingsFacade, HostSettingsFacadeProvider.GetOrCreate())) { @@ -482,7 +482,7 @@ public sealed class PluginRuntimeService : IDisposable { _ = sender; - var pluginSnapshot = PluginAppearanceSnapshotMapper.FromMaterialColorSnapshot(snapshot); + var pluginSnapshot = AirAppAppearanceSnapshotMapper.FromMaterialColorSnapshot(snapshot); var changedProperties = new[] { AppearanceProperty.ThemeVariant, @@ -495,26 +495,26 @@ public sealed class PluginRuntimeService : IDisposable AppearanceProperty.WallpaperSeedCandidates }; - foreach (var loadedPlugin in _loadedPlugins) + foreach (var loadedAirApp in _loadedAirApps) { - if (loadedPlugin.RuntimeContext.Appearance is PluginAppearanceContext appearanceContext) + if (loadedAirApp.RuntimeContext.Appearance is AirAppAppearanceContext appearanceContext) { appearanceContext.UpdateSnapshot(pluginSnapshot, changedProperties); } } } - private void UnloadInstalledPlugins() + private void UnloadInstalledAirApps() { - for (var i = _loadedPlugins.Count - 1; i >= 0; i--) + for (var i = _loadedAirApps.Count - 1; i >= 0; i--) { - var pluginId = _loadedPlugins[i].Manifest.Id; + var pluginId = _loadedAirApps[i].Manifest.Id; _exportRegistry.RemoveExports(pluginId); - _settingsCatalogService.RemovePluginSections(pluginId); - _loadedPlugins[i].Dispose(); + _settingsCatalogService.RemoveAirAppSections(pluginId); + _loadedAirApps[i].Dispose(); } - _loadedPlugins.Clear(); + _loadedAirApps.Clear(); _exportRegistry.Clear(); _loadResults.Clear(); _catalog.Clear(); @@ -530,41 +530,41 @@ public sealed class PluginRuntimeService : IDisposable : new HashSet(StringComparer.OrdinalIgnoreCase); } - private IReadOnlyList DiscoverCandidates(List failures) + private IReadOnlyList DiscoverCandidates(List failures) { - var candidates = new List(); + var candidates = new List(); - foreach (var packagePath in EnumerateCandidatePaths($"*{PluginSdkInfo.PackageFileExtension}")) + foreach (var packagePath in EnumerateCandidatePaths($"*{AirAppSdkInfo.PackageFileExtension}")) { try { var manifest = ReadManifestFromPackage(packagePath); - candidates.Add(new PluginCandidate(packagePath, manifest, PluginCatalogSourceKind.Package)); + candidates.Add(new AirAppCandidate(packagePath, manifest, AirAppCatalogSourceKind.Package)); } catch (Exception ex) { - var failure = PluginLoadResult.Failure(packagePath, null, ex); + var failure = AirAppLoadResult.Failure(packagePath, null, ex); failures.Add(failure); - LogPluginFailure("ManifestValidation", failure, treatAsError: false); + LogAirAppFailure("ManifestValidation", failure, treatAsError: false); } } - foreach (var manifestPath in EnumerateCandidatePaths("plugin.json")) + foreach (var manifestPath in EnumerateCandidatePaths(AirAppSdkInfo.ManifestFileName)) { try { - var manifest = PluginManifest.Load(manifestPath); - candidates.Add(new PluginCandidate(manifestPath, manifest, PluginCatalogSourceKind.Manifest)); + var manifest = AirAppManifest.Load(manifestPath); + candidates.Add(new AirAppCandidate(manifestPath, manifest, AirAppCatalogSourceKind.Manifest)); } catch (Exception ex) { - var failure = PluginLoadResult.Failure(manifestPath, null, ex); + var failure = AirAppLoadResult.Failure(manifestPath, null, ex); failures.Add(failure); - LogPluginFailure("ManifestValidation", failure, treatAsError: false); + LogAirAppFailure("ManifestValidation", failure, treatAsError: false); } } - DiscoverDevPluginCandidates(candidates, failures); + DiscoverDevAirAppCandidates(candidates, failures); return candidates .OrderByDescending(candidate => candidate.SourceKind) @@ -572,31 +572,31 @@ public sealed class PluginRuntimeService : IDisposable .ToArray(); } - private void DiscoverDevPluginCandidates(List candidates, List failures) + private void DiscoverDevAirAppCandidates(List candidates, List failures) { - var devOptions = DevPluginOptions.Current; + var devOptions = DevAirAppOptions.Current; if (!devOptions.IsDevMode || devOptions.DevPluginPaths.Count == 0) { return; } - AppLogger.Info("DevPlugin", $"Scanning developer plugin paths. Count={devOptions.DevPluginPaths.Count}."); + AppLogger.Info("DevAirApp", $"Scanning developer plugin paths. Count={devOptions.DevPluginPaths.Count}."); foreach (var devPath in devOptions.DevPluginPaths) { - if (File.Exists(devPath) && string.Equals(Path.GetExtension(devPath), PluginSdkInfo.PackageFileExtension, StringComparison.OrdinalIgnoreCase)) + if (File.Exists(devPath) && string.Equals(Path.GetExtension(devPath), AirAppSdkInfo.PackageFileExtension, StringComparison.OrdinalIgnoreCase)) { try { var manifest = ReadManifestFromPackage(devPath); - candidates.Add(new PluginCandidate(devPath, manifest, PluginCatalogSourceKind.DevPlugin)); - AppLogger.Info("DevPlugin", $"Found developer plugin package. PluginId='{manifest.Id}'; Path='{devPath}'."); + candidates.Add(new AirAppCandidate(devPath, manifest, AirAppCatalogSourceKind.DevAirApp)); + AppLogger.Info("DevAirApp", $"Found developer plugin package. AirAppId='{manifest.Id}'; Path='{devPath}'."); } catch (Exception ex) { - var failure = PluginLoadResult.Failure(devPath, null, ex); + var failure = AirAppLoadResult.Failure(devPath, null, ex); failures.Add(failure); - AppLogger.Warn("DevPlugin", $"Failed to read developer plugin package '{devPath}'.", ex); + AppLogger.Warn("DevAirApp", $"Failed to read developer plugin package '{devPath}'.", ex); } continue; @@ -604,70 +604,70 @@ public sealed class PluginRuntimeService : IDisposable if (Directory.Exists(devPath)) { - var manifestPath = Path.Combine(devPath, PluginSdkInfo.ManifestFileName); + var manifestPath = Path.Combine(devPath, AirAppSdkInfo.ManifestFileName); if (File.Exists(manifestPath)) { try { - var manifest = PluginManifest.Load(manifestPath); - candidates.Add(new PluginCandidate(manifestPath, manifest, PluginCatalogSourceKind.DevPlugin)); - AppLogger.Info("DevPlugin", $"Found developer plugin manifest. PluginId='{manifest.Id}'; Path='{manifestPath}'."); + var manifest = AirAppManifest.Load(manifestPath); + candidates.Add(new AirAppCandidate(manifestPath, manifest, AirAppCatalogSourceKind.DevAirApp)); + AppLogger.Info("DevAirApp", $"Found developer plugin manifest. AirAppId='{manifest.Id}'; Path='{manifestPath}'."); } catch (Exception ex) { - var failure = PluginLoadResult.Failure(manifestPath, null, ex); + var failure = AirAppLoadResult.Failure(manifestPath, null, ex); failures.Add(failure); - AppLogger.Warn("DevPlugin", $"Failed to load developer plugin manifest '{manifestPath}'.", ex); + AppLogger.Warn("DevAirApp", $"Failed to load developer plugin manifest '{manifestPath}'.", ex); } } else { - AppLogger.Warn("DevPlugin", $"Developer plugin directory '{devPath}' does not contain '{PluginSdkInfo.ManifestFileName}'. Skipping."); + AppLogger.Warn("DevAirApp", $"Developer plugin directory '{devPath}' does not contain '{AirAppSdkInfo.ManifestFileName}'. Skipping."); } continue; } - AppLogger.Warn("DevPlugin", $"Developer plugin path '{devPath}' is neither a file nor a directory. Skipping."); + AppLogger.Warn("DevAirApp", $"Developer plugin path '{devPath}' is neither a file nor a directory. Skipping."); } } private IEnumerable EnumerateCandidatePaths(string searchPattern) { - var runtimeRootDirectory = EnsureTrailingSeparator(Path.Combine(Path.GetFullPath(PluginsDirectory), ".runtime")); + var runtimeRootDirectory = EnsureTrailingSeparator(Path.Combine(Path.GetFullPath(AirAppsDirectory), ".runtime")); return Directory - .EnumerateFiles(PluginsDirectory, searchPattern, SearchOption.AllDirectories) + .EnumerateFiles(AirAppsDirectory, searchPattern, SearchOption.AllDirectories) .Select(Path.GetFullPath) .Where(path => !path.StartsWith(runtimeRootDirectory, StringComparison.OrdinalIgnoreCase)) .OrderBy(path => path, StringComparer.OrdinalIgnoreCase); } - private static PluginManifest ReadManifestFromPackage(string packagePath) + private static AirAppManifest ReadManifestFromPackage(string packagePath) { using var archive = ZipFile.OpenRead(packagePath); var entries = archive.Entries - .Where(entry => string.Equals(entry.Name, "plugin.json", StringComparison.OrdinalIgnoreCase)) + .Where(entry => string.Equals(entry.Name, AirAppSdkInfo.ManifestFileName, StringComparison.OrdinalIgnoreCase)) .ToArray(); if (entries.Length == 0) { - throw new InvalidOperationException($"Plugin package '{packagePath}' does not contain 'plugin.json'."); + throw new InvalidOperationException($"AirApp package '{packagePath}' does not contain '{AirAppSdkInfo.ManifestFileName}'."); } if (entries.Length > 1) { - throw new InvalidOperationException($"Plugin package '{packagePath}' contains multiple 'plugin.json' files."); + throw new InvalidOperationException($"AirApp package '{packagePath}' contains multiple '{AirAppSdkInfo.ManifestFileName}' files."); } using var stream = entries[0].Open(); - return PluginManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); + return AirAppManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); } - private bool RemoveExistingPluginPackages(string pluginId, string packagePathToKeep) + private bool RemoveExistingAirAppPackages(string pluginId, string packagePathToKeep) { var replacedExisting = false; - foreach (var existingPackagePath in EnumerateCandidatePaths($"*{PluginSdkInfo.PackageFileExtension}")) + foreach (var existingPackagePath in EnumerateCandidatePaths($"*{AirAppSdkInfo.PackageFileExtension}")) { if (string.Equals( Path.GetFullPath(existingPackagePath), @@ -685,7 +685,7 @@ public sealed class PluginRuntimeService : IDisposable continue; } - FileOperationRetryHelper.DeleteFileWithRetry(existingPackagePath, "PluginRuntime"); + FileOperationRetryHelper.DeleteFileWithRetry(existingPackagePath, "AirAppRuntime"); replacedExisting = true; } catch @@ -697,10 +697,10 @@ public sealed class PluginRuntimeService : IDisposable return replacedExisting; } - private void UpdateCatalogAfterPackageInstall(PluginManifest manifest, string destinationPath) + private void UpdateCatalogAfterPackageInstall(AirAppManifest manifest, string destinationPath) { var isEnabled = !GetDisabledPluginIds().Contains(manifest.Id); - var entry = new PluginCatalogEntry( + var entry = new AirAppCatalogEntry( manifest, destinationPath, IsPackage: true, @@ -726,7 +726,7 @@ public sealed class PluginRuntimeService : IDisposable { var invalidChars = Path.GetInvalidFileNameChars(); var fileName = new string(pluginId.Select(ch => invalidChars.Contains(ch) ? '_' : ch).ToArray()); - return fileName + PluginSdkInfo.PackageFileExtension; + return fileName + AirAppSdkInfo.PackageFileExtension; } private static string EnsureTrailingSeparator(string path) @@ -736,10 +736,10 @@ public sealed class PluginRuntimeService : IDisposable : path + Path.DirectorySeparatorChar; } - private static PluginLoaderOptions CreateOptions() + private static AirAppLoaderOptions CreateOptions() { - var devOptions = DevPluginOptions.Current; - var options = new PluginLoaderOptions { IsDevMode = devOptions.IsDevMode }; + var devOptions = DevAirAppOptions.Current; + var options = new AirAppLoaderOptions { IsDevMode = devOptions.IsDevMode }; AddSharedAssembly(options, typeof(App).Assembly); AddSharedAssembly(options, typeof(IServiceCollection).Assembly); AddSharedAssembly(options, typeof(HostBuilderContext).Assembly); @@ -768,7 +768,7 @@ public sealed class PluginRuntimeService : IDisposable return options; } - private static void AddSharedAssembly(PluginLoaderOptions options, Assembly assembly) + private static void AddSharedAssembly(AirAppLoaderOptions options, Assembly assembly) { var assemblyName = assembly.GetName().Name; if (!string.IsNullOrWhiteSpace(assemblyName)) @@ -779,7 +779,7 @@ public sealed class PluginRuntimeService : IDisposable private void MergeDevSettingsFromSnapshot() { - var devOptions = DevPluginOptions.Current; + var devOptions = DevAirAppOptions.Current; try { @@ -787,66 +787,66 @@ public sealed class PluginRuntimeService : IDisposable if (snapshot.IsDevModeEnabled && !devOptions.IsDevMode) { - devOptions.ApplySettingsFromSnapshot(isDevMode: true, devPluginPath: snapshot.DevPluginPath); - AppLogger.Info("DevPlugin", $"Developer mode enabled via settings. DevPluginPath='{snapshot.DevPluginPath}'."); + devOptions.ApplySettingsFromSnapshot(isDevMode: true, devAirAppPath: snapshot.DevPluginPath); + AppLogger.Info("DevAirApp", $"Developer mode enabled via settings. DevPluginPath='{snapshot.DevPluginPath}'."); } else if (!string.IsNullOrWhiteSpace(snapshot.DevPluginPath) && string.IsNullOrWhiteSpace(devOptions.DevPluginPath)) { - devOptions.ApplySettingsFromSnapshot(isDevMode: devOptions.IsDevMode, devPluginPath: snapshot.DevPluginPath); - AppLogger.Info("DevPlugin", $"Developer plugin path merged from settings. DevPluginPath='{snapshot.DevPluginPath}'."); + devOptions.ApplySettingsFromSnapshot(isDevMode: devOptions.IsDevMode, devAirAppPath: snapshot.DevPluginPath); + AppLogger.Info("DevAirApp", $"Developer plugin path merged from settings. DevPluginPath='{snapshot.DevPluginPath}'."); } } catch (Exception ex) { - AppLogger.Warn("DevPlugin", "Failed to merge developer settings from snapshot.", ex); + AppLogger.Warn("DevAirApp", "Failed to merge developer settings from snapshot.", ex); } } - private void CollectContributions(LoadedPlugin loadedPlugin) + private void CollectContributions(LoadedAirApp loadedAirApp) { - _exportRegistry.ReplaceExports(loadedPlugin.Manifest.Id, loadedPlugin.ExportedServices); + _exportRegistry.ReplaceExports(loadedAirApp.Manifest.Id, loadedAirApp.ExportedServices); - _settingsCatalogService.RegisterPluginSections(loadedPlugin.Manifest.Id, loadedPlugin.SettingsSections); + _settingsCatalogService.RegisterAirAppSections(loadedAirApp.Manifest.Id, loadedAirApp.SettingsSections); _settingsSections.RemoveAll(entry => string.Equals( - entry.Plugin.Manifest.Id, - loadedPlugin.Manifest.Id, + entry.AirApp.Manifest.Id, + loadedAirApp.Manifest.Id, StringComparison.OrdinalIgnoreCase)); _desktopComponentEditors.RemoveAll(entry => string.Equals( - entry.Plugin.Manifest.Id, - loadedPlugin.Manifest.Id, + entry.AirApp.Manifest.Id, + loadedAirApp.Manifest.Id, StringComparison.OrdinalIgnoreCase)); - foreach (var settingsSection in loadedPlugin.SettingsSections) + foreach (var settingsSection in loadedAirApp.SettingsSections) { - _settingsSections.Add(new PluginSettingsSectionContribution(loadedPlugin, settingsSection)); + _settingsSections.Add(new AirAppSettingsSectionContribution(loadedAirApp, settingsSection)); } - foreach (var desktopComponent in loadedPlugin.DesktopComponents) + foreach (var desktopComponent in loadedAirApp.DesktopComponents) { - _desktopComponents.Add(new PluginDesktopComponentContribution(loadedPlugin, desktopComponent)); + _desktopComponents.Add(new AirAppDesktopComponentContribution(loadedAirApp, desktopComponent)); } - foreach (var desktopComponentEditor in loadedPlugin.DesktopComponentEditors) + foreach (var desktopComponentEditor in loadedAirApp.DesktopComponentEditors) { - _desktopComponentEditors.Add(new PluginDesktopComponentEditorContribution(loadedPlugin, desktopComponentEditor)); + _desktopComponentEditors.Add(new AirAppDesktopComponentEditorContribution(loadedAirApp, desktopComponentEditor)); } if (_publicIpcHostService is not null) { - foreach (var publicIpcService in loadedPlugin.PublicIpcServices) + foreach (var publicIpcService in loadedAirApp.PublicIpcServices) { _publicIpcHostService.RegisterPublicService( publicIpcService.ContractType, publicIpcService.Implementation, publicIpcService.ObjectId, - loadedPlugin.Manifest.Id, + loadedAirApp.Manifest.Id, publicIpcService.NotifyIds); } } } - private void RegisterSharedContractsForLoad(PluginManifest manifest) + private void RegisterSharedContractsForLoad(AirAppManifest manifest) { foreach (var assemblyName in _sharedContractManager.PrepareForLoad(manifest)) { @@ -857,25 +857,25 @@ public sealed class PluginRuntimeService : IDisposable } } - private void ApplyPendingPluginDeletions() + private void ApplyPendingAirAppDeletions() { - var pendingPaths = ReadPendingPluginDeletions(); + var pendingPaths = ReadPendingAirAppDeletions(); var remainingPaths = new List(); foreach (var path in pendingPaths) { - if (!TryDeletePluginTarget(path)) + if (!TryDeleteAirAppTarget(path)) { remainingPaths.Add(path); } } - SavePendingPluginDeletions(remainingPaths); + SavePendingAirAppDeletions(remainingPaths); CleanupPendingDeletionDirectory(); } private void ApplyPendingPluginOperations() { - var pendingService = new PendingPluginUpgradeService(PluginsDirectory); + var pendingService = new PendingAirAppUpgradeService(AirAppsDirectory); var result = pendingService.ApplyPendingOperations(manifest => _sharedContractManager.EnsureInstalled(manifest)); if (result.SuccessCount == 0 && result.FailureCount == 0) { @@ -883,20 +883,20 @@ public sealed class PluginRuntimeService : IDisposable } AppLogger.Info( - "PluginRuntime", - $"Pending plugin operations applied before discovery. Success={result.SuccessCount}; Failure={result.FailureCount}; PluginsDirectory='{PluginsDirectory}'."); + "AirAppRuntime", + $"Pending plugin operations applied before discovery. Success={result.SuccessCount}; Failure={result.FailureCount}; AirAppsDirectory='{AirAppsDirectory}'."); foreach (var failure in result.Failures) { AppLogger.Warn( - "PluginRuntime", - $"Pending plugin operation failed and will remain queued. PluginId='{failure.PluginId}'; Operation='{failure.Operation}'; Error='{failure.ErrorMessage}'."); + "AirAppRuntime", + $"Pending plugin operation failed and will remain queued. AirAppId='{failure.PluginId}'; Operation='{failure.Operation}'; Error='{failure.ErrorMessage}'."); } } private void CleanupPendingDeletionDirectory() { - var pendingDeletionDir = Path.Combine(PluginsDirectory, ".pending-deletions"); + var pendingDeletionDir = Path.Combine(AirAppsDirectory, ".pending-deletions"); if (!Directory.Exists(pendingDeletionDir)) { return; @@ -928,7 +928,7 @@ public sealed class PluginRuntimeService : IDisposable } } - private string ResolvePluginRemovalTargetPath(PluginCatalogEntry entry) + private string ResolveAirAppRemovalTargetPath(AirAppCatalogEntry entry) { if (entry.IsPackage) { @@ -937,7 +937,7 @@ public sealed class PluginRuntimeService : IDisposable var fullSourcePath = Path.GetFullPath(entry.SourcePath); if (File.Exists(fullSourcePath) && - string.Equals(Path.GetFileName(fullSourcePath), "plugin.json", StringComparison.OrdinalIgnoreCase)) + string.Equals(Path.GetFileName(fullSourcePath), AirAppSdkInfo.ManifestFileName, StringComparison.OrdinalIgnoreCase)) { return Path.GetDirectoryName(fullSourcePath) ?? fullSourcePath; } @@ -945,7 +945,7 @@ public sealed class PluginRuntimeService : IDisposable return fullSourcePath; } - private static bool TryDeletePluginTarget(string targetPath) + private static bool TryDeleteAirAppTarget(string targetPath) { try { @@ -966,19 +966,19 @@ public sealed class PluginRuntimeService : IDisposable } } - private void RegisterPendingPluginDeletion(string targetPath) + private void RegisterPendingAirAppDeletion(string targetPath) { - var pendingPaths = ReadPendingPluginDeletions(); + var pendingPaths = ReadPendingAirAppDeletions(); if (pendingPaths.Contains(targetPath, StringComparer.OrdinalIgnoreCase)) { return; } pendingPaths.Add(targetPath); - SavePendingPluginDeletions(pendingPaths); + SavePendingAirAppDeletions(pendingPaths); } - private List ReadPendingPluginDeletions() + private List ReadPendingAirAppDeletions() { var pendingDeletionFilePath = GetPendingDeletionFilePath(); if (!File.Exists(pendingDeletionFilePath)) @@ -1002,7 +1002,7 @@ public sealed class PluginRuntimeService : IDisposable } } - private void SavePendingPluginDeletions(IEnumerable pendingPaths) + private void SavePendingAirAppDeletions(IEnumerable pendingPaths) { var pendingDeletionFilePath = GetPendingDeletionFilePath(); var normalizedPaths = pendingPaths @@ -1022,7 +1022,7 @@ public sealed class PluginRuntimeService : IDisposable return; } - Directory.CreateDirectory(PluginsDirectory); + Directory.CreateDirectory(AirAppsDirectory); var json = JsonSerializer.Serialize(normalizedPaths, new JsonSerializerOptions { WriteIndented = true @@ -1032,25 +1032,25 @@ public sealed class PluginRuntimeService : IDisposable private string GetPendingDeletionFilePath() { - return Path.Combine(PluginsDirectory, PendingDeletionFileName); + return Path.Combine(AirAppsDirectory, PendingDeletionFileName); } - private static void LogPluginFailure(string stage, PluginLoadResult result, bool treatAsError) + private static void LogAirAppFailure(string stage, AirAppLoadResult result, bool treatAsError) { var manifest = result.Manifest; var message = - $"Plugin load issue. Stage='{stage}'; PluginId='{manifest?.Id ?? ""}'; SourcePath='{result.SourcePath}'; ManifestVersion='{manifest?.Version ?? ""}'; ApiVersion='{manifest?.ApiVersion ?? ""}'; Error='{result.Error?.Message ?? ""}'."; + $"AirApp load issue. Stage='{stage}'; AirAppId='{manifest?.Id ?? ""}'; SourcePath='{result.SourcePath}'; ManifestVersion='{manifest?.Version ?? ""}'; ApiVersion='{manifest?.ApiVersion ?? ""}'; Error='{result.Error?.Message ?? ""}'."; if (treatAsError) { - AppLogger.Error("PluginRuntime", message, result.Error); + AppLogger.Error("AirAppRuntime", message, result.Error); return; } - AppLogger.Warn("PluginRuntime", message, result.Error); + AppLogger.Warn("AirAppRuntime", message, result.Error); } - private void RemovePluginFromSnapshot(string pluginId) + private void RemoveAirAppFromSnapshot(string pluginId) { var snapshot = LoadAppSettingsSnapshot(); if (snapshot.DisabledPluginIds.RemoveAll(id => string.Equals(id, pluginId, StringComparison.OrdinalIgnoreCase)) > 0) @@ -1061,40 +1061,40 @@ public sealed class PluginRuntimeService : IDisposable private AppSettingsSnapshot LoadAppSettingsSnapshot() { - return _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + return _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); } private void SaveAppSettingsSnapshot(AppSettingsSnapshot snapshot) { - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, snapshot); + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, snapshot); } - private void RemovePluginFromCatalog(string pluginId) + private void RemoveAirAppFromCatalog(string pluginId) { _catalog.RemoveAll(entry => string.Equals(entry.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); - _settingsSections.RemoveAll(entry => string.Equals(entry.Plugin.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); - _desktopComponents.RemoveAll(entry => string.Equals(entry.Plugin.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); + _settingsSections.RemoveAll(entry => string.Equals(entry.AirApp.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); + _desktopComponents.RemoveAll(entry => string.Equals(entry.AirApp.Manifest.Id, pluginId, StringComparison.OrdinalIgnoreCase)); _loadResults.RemoveAll(entry => string.Equals(entry.Manifest?.Id, pluginId, StringComparison.OrdinalIgnoreCase)); - _settingsCatalogService.RemovePluginSections(pluginId); + _settingsCatalogService.RemoveAirAppSections(pluginId); } - private enum PluginCatalogSourceKind + private enum AirAppCatalogSourceKind { Package = 0, Manifest = 1, - DevPlugin = 2 + DevAirApp = 2 } - private sealed record PluginCandidate( + private sealed record AirAppCandidate( string SourcePath, - PluginManifest Manifest, - PluginCatalogSourceKind SourceKind); + AirAppManifest Manifest, + AirAppCatalogSourceKind SourceKind); - private sealed class PluginHostServiceProvider : IServiceProvider + private sealed class AirAppHostServiceProvider : IServiceProvider { - private readonly IPluginPackageManager _packageManager; + private readonly IAirAppPackageManager _packageManager; private readonly IHostApplicationLifecycle _applicationLifecycle; - private readonly IPluginExportRegistry _exportRegistry; + private readonly IAirAppExportRegistry _exportRegistry; private readonly ISettingsFacadeService _settingsFacade; private readonly ISettingsService _settingsService; private readonly ISettingsCatalog _settingsCatalog; @@ -1102,10 +1102,10 @@ public sealed class PluginRuntimeService : IDisposable private readonly IMaterialColorService _materialColorService; private readonly IExternalIpcNotificationPublisher? _externalIpcNotificationPublisher; - public PluginHostServiceProvider( - IPluginPackageManager packageManager, + public AirAppHostServiceProvider( + IAirAppPackageManager packageManager, IHostApplicationLifecycle applicationLifecycle, - IPluginExportRegistry exportRegistry, + IAirAppExportRegistry exportRegistry, ISettingsFacadeService settingsFacade, ISettingsService settingsService, ISettingsCatalog settingsCatalog, @@ -1124,7 +1124,7 @@ public sealed class PluginRuntimeService : IDisposable public object? GetService(Type serviceType) { - if (serviceType == typeof(IPluginPackageManager)) + if (serviceType == typeof(IAirAppPackageManager)) { return _packageManager; } @@ -1134,7 +1134,7 @@ public sealed class PluginRuntimeService : IDisposable return _applicationLifecycle; } - if (serviceType == typeof(IPluginExportRegistry)) + if (serviceType == typeof(IAirAppExportRegistry)) { return _exportRegistry; } @@ -1156,7 +1156,7 @@ public sealed class PluginRuntimeService : IDisposable if (serviceType == typeof(IAppearanceThemeService)) { - // Compatibility-only. Plugin appearance snapshots are still sourced from the material pipeline. + // Compatibility-only. AirApp appearance snapshots are still sourced from the material pipeline. return _appearanceThemeService; } @@ -1174,23 +1174,23 @@ public sealed class PluginRuntimeService : IDisposable } } - private sealed class PluginRuntimePackageManager : IPluginPackageManager + private sealed class AirAppRuntimePackageManager : IAirAppPackageManager { - private readonly PluginRuntimeService _runtimeService; + private readonly AirAppRuntimeService _runtimeService; - public PluginRuntimePackageManager(PluginRuntimeService runtimeService) + public AirAppRuntimePackageManager(AirAppRuntimeService runtimeService) { _runtimeService = runtimeService; } - public IReadOnlyList GetInstalledPlugins() + public IReadOnlyList GetInstalledAirApps() { - return _runtimeService.GetInstalledPluginsSnapshot(); + return _runtimeService.GetInstalledAirAppsSnapshot(); } - public PluginPackageInstallResult InstallPackage(string packagePath) + public AirAppPackageInstallResult InstallPackage(string packagePath) { - return _runtimeService.InstallPluginPackageCore(packagePath); + return _runtimeService.InstallAirAppPackageCore(packagePath); } } } diff --git a/desktop/LanMountainDesktop/plugins/PluginScopedSettingsService.cs b/desktop/LanMountainDesktop/AirApps/AirAppScopedSettingsService.cs similarity index 80% rename from desktop/LanMountainDesktop/plugins/PluginScopedSettingsService.cs rename to desktop/LanMountainDesktop/AirApps/AirAppScopedSettingsService.cs index f751a80..9be51f6 100644 --- a/desktop/LanMountainDesktop/plugins/PluginScopedSettingsService.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppScopedSettingsService.cs @@ -1,20 +1,20 @@ using System; using System.Collections.Generic; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; -internal sealed class PluginScopedSettingsService : IPluginSettingsService +internal sealed class AirAppScopedSettingsService : IAirAppSettingsService { private readonly ISettingsService _settingsService; - public PluginScopedSettingsService(string pluginId, ISettingsService settingsService) + public AirAppScopedSettingsService(string pluginId, ISettingsService settingsService) { - PluginId = string.IsNullOrWhiteSpace(pluginId) ? "__unknown__" : pluginId.Trim(); + AirAppId = string.IsNullOrWhiteSpace(pluginId) ? "__unknown__" : pluginId.Trim(); _settingsService = settingsService ?? throw new ArgumentNullException(nameof(settingsService)); } - public string PluginId { get; } + public string AirAppId { get; } public IComponentSettingsAccessor GetComponentAccessor(string componentId, string? placementId) { @@ -24,7 +24,7 @@ internal sealed class PluginScopedSettingsService : IPluginSettingsService public T LoadComponentSection(string componentId, string? placementId, string sectionId) where T : new() { return _settingsService.LoadSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, componentId, BuildScopedSectionId(sectionId), placementId); @@ -38,7 +38,7 @@ internal sealed class PluginScopedSettingsService : IPluginSettingsService IReadOnlyCollection? changedKeys = null) { _settingsService.SaveSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, componentId, BuildScopedSectionId(sectionId), section, @@ -49,7 +49,7 @@ internal sealed class PluginScopedSettingsService : IPluginSettingsService public void DeleteComponentSection(string componentId, string? placementId, string sectionId) { _settingsService.DeleteSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, componentId, BuildScopedSectionId(sectionId), placementId); @@ -58,15 +58,15 @@ internal sealed class PluginScopedSettingsService : IPluginSettingsService private string BuildScopedSectionId(string sectionId) { var normalizedSectionId = string.IsNullOrWhiteSpace(sectionId) ? "__default__" : sectionId.Trim(); - return $"{PluginId}:{normalizedSectionId}"; + return $"{AirAppId}:{normalizedSectionId}"; } private sealed class ScopedComponentAccessor : IComponentSettingsAccessor { - private readonly PluginScopedSettingsService _owner; + private readonly AirAppScopedSettingsService _owner; private readonly IComponentSettingsAccessor _inner; - public ScopedComponentAccessor(PluginScopedSettingsService owner, IComponentSettingsAccessor inner) + public ScopedComponentAccessor(AirAppScopedSettingsService owner, IComponentSettingsAccessor inner) { _owner = owner; _inner = inner; @@ -103,12 +103,12 @@ internal sealed class PluginScopedSettingsService : IPluginSettingsService public T? GetValue(string key) { - return _inner.GetValue($"{_owner.PluginId}:{key}"); + return _inner.GetValue($"{_owner.AirAppId}:{key}"); } public void SetValue(string key, T value, IReadOnlyCollection? changedKeys = null) { - _inner.SetValue($"{_owner.PluginId}:{key}", value, changedKeys); + _inner.SetValue($"{_owner.AirAppId}:{key}", value, changedKeys); } } } diff --git a/desktop/LanMountainDesktop/plugins/PluginSharedContractManager.cs b/desktop/LanMountainDesktop/AirApps/AirAppSharedContractManager.cs similarity index 92% rename from desktop/LanMountainDesktop/plugins/PluginSharedContractManager.cs rename to desktop/LanMountainDesktop/AirApps/AirAppSharedContractManager.cs index fb74751..4257145 100644 --- a/desktop/LanMountainDesktop/plugins/PluginSharedContractManager.cs +++ b/desktop/LanMountainDesktop/AirApps/AirAppSharedContractManager.cs @@ -7,13 +7,13 @@ using System.Reflection; using System.Runtime.Loader; using System.Security.Cryptography; using System.Threading; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; -using LanMountainDesktop.Services.PluginMarket; +using LanMountainDesktop.Services.AirAppMarket; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -internal sealed class PluginSharedContractManager : IDisposable +internal sealed class AirAppSharedContractManager : IDisposable { private readonly string _contractsDirectory; private readonly AirAppMarketIndexService _indexService; @@ -22,7 +22,7 @@ internal sealed class PluginSharedContractManager : IDisposable private readonly Dictionary _loadedContracts = new(StringComparer.OrdinalIgnoreCase); - public PluginSharedContractManager(string dataDirectory) + public AirAppSharedContractManager(string dataDirectory) { ArgumentException.ThrowIfNullOrWhiteSpace(dataDirectory); @@ -40,7 +40,7 @@ internal sealed class PluginSharedContractManager : IDisposable public string ContractsDirectory => _contractsDirectory; - public void EnsureInstalled(PluginManifest manifest, CancellationToken cancellationToken = default) + public void EnsureInstalled(AirAppManifest manifest, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(manifest); @@ -51,7 +51,7 @@ internal sealed class PluginSharedContractManager : IDisposable var document = LoadIndex(cancellationToken); AppLogger.Info( - "PluginSharedContracts", + "AirAppSharedContracts", $"Shared contract index loaded for plugin '{manifest.Id}'. SourceContracts={document.Contracts.Count}."); foreach (var reference in manifest.SharedContracts) { @@ -59,7 +59,7 @@ internal sealed class PluginSharedContractManager : IDisposable } } - public IReadOnlyList PrepareForLoad(PluginManifest manifest, CancellationToken cancellationToken = default) + public IReadOnlyList PrepareForLoad(AirAppManifest manifest, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(manifest); @@ -77,15 +77,15 @@ internal sealed class PluginSharedContractManager : IDisposable { document ??= LoadIndex(cancellationToken); AppLogger.Info( - "PluginSharedContracts", - $"Installing missing shared contract during plugin load. PluginId='{manifest.Id}'; ContractId='{reference.Id}'; Version='{reference.Version}'; Destination='{assemblyPath}'."); + "AirAppSharedContracts", + $"Installing missing shared contract during plugin load. AirAppId='{manifest.Id}'; ContractId='{reference.Id}'; Version='{reference.Version}'; Destination='{assemblyPath}'."); EnsureInstalled(document, reference, cancellationToken); } if (!File.Exists(assemblyPath)) { throw new InvalidOperationException( - $"Plugin '{manifest.Id}' requires shared contract '{reference.Id}' version '{reference.Version}', but '{assemblyPath}' is not installed. Install the dependency from the market first."); + $"AirApp '{manifest.Id}' requires shared contract '{reference.Id}' version '{reference.Version}', but '{assemblyPath}' is not installed. Install the dependency from the market first."); } var loaded = LoadSharedAssembly(reference, assemblyPath); @@ -103,7 +103,7 @@ internal sealed class PluginSharedContractManager : IDisposable private void EnsureInstalled( AirAppMarketIndexDocument document, - PluginSharedContractReference reference, + AirAppSharedContractReference reference, CancellationToken cancellationToken) { var entry = document.Contracts.FirstOrDefault(candidate => @@ -154,7 +154,7 @@ internal sealed class PluginSharedContractManager : IDisposable ValidateInstalledFile(temporaryPath, entry); File.Move(temporaryPath, destinationPath, overwrite: true); AppLogger.Info( - "PluginSharedContracts", + "AirAppSharedContracts", $"Installed shared contract. ContractId='{reference.Id}'; Version='{reference.Version}'; Source='{resolvedSource}'; Destination='{destinationPath}'."); } finally @@ -165,7 +165,7 @@ internal sealed class PluginSharedContractManager : IDisposable private AirAppMarketIndexDocument LoadIndex(CancellationToken cancellationToken) { - AppLogger.Info("PluginSharedContracts", "Loading market index for shared contract resolution."); + AppLogger.Info("AirAppSharedContracts", "Loading market index for shared contract resolution."); var result = _indexService.LoadAsync(cancellationToken).GetAwaiter().GetResult(); if (!result.Success || result.Document is null) { @@ -174,14 +174,14 @@ internal sealed class PluginSharedContractManager : IDisposable } AppLogger.Info( - "PluginSharedContracts", + "AirAppSharedContracts", $"Market index ready. Source='{result.Source}'; Location='{result.SourceLocation}'; Warning='{result.WarningMessage ?? string.Empty}'."); return result.Document; } private LoadedSharedContract LoadSharedAssembly( - PluginSharedContractReference reference, + AirAppSharedContractReference reference, string assemblyPath) { var assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath).Name @@ -247,7 +247,7 @@ internal sealed class PluginSharedContractManager : IDisposable } } - private string GetInstalledAssemblyPath(PluginSharedContractReference reference) + private string GetInstalledAssemblyPath(AirAppSharedContractReference reference) { return Path.Combine( _contractsDirectory, diff --git a/desktop/LanMountainDesktop/plugins/DevPluginOptions.cs b/desktop/LanMountainDesktop/AirApps/DevAirAppOptions.cs similarity index 85% rename from desktop/LanMountainDesktop/plugins/DevPluginOptions.cs rename to desktop/LanMountainDesktop/AirApps/DevAirAppOptions.cs index 3be9a48..47629c4 100644 --- a/desktop/LanMountainDesktop/plugins/DevPluginOptions.cs +++ b/desktop/LanMountainDesktop/AirApps/DevAirAppOptions.cs @@ -4,9 +4,9 @@ using System.Linq; using LanMountainDesktop.Services; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -public sealed class DevPluginOptions +public sealed class DevAirAppOptions { private static readonly string[] DevPluginPathArgs = ["--dev-plugin", "-dp"]; private static readonly string[] DevModeArgs = ["--dev-mode", "-dev"]; @@ -14,7 +14,7 @@ public sealed class DevPluginOptions private static readonly string EnvDevPluginPath = "LMD_DEV_PLUGIN"; private static readonly string EnvDevMode = "LMD_DEV_MODE"; - public static DevPluginOptions Current { get; } = new(); + public static DevAirAppOptions Current { get; } = new(); public bool IsDevMode { get; private set; } @@ -24,9 +24,9 @@ public sealed class DevPluginOptions public IReadOnlyList DevPluginPaths { get; private set; } = Array.Empty(); - private DevPluginOptions() { } + private DevAirAppOptions() { } - public static DevPluginOptions Parse(string[] args) + public static DevAirAppOptions Parse(string[] args) { var options = Current; @@ -49,29 +49,29 @@ public sealed class DevPluginOptions if (options.IsDevMode) { AppLogger.Info( - "DevPlugin", + "DevAirApp", $"Developer mode enabled. DevPluginPath='{options.DevPluginPath}'; EnableHotReload={options.EnableHotReload}; ResolvedPaths={options.DevPluginPaths.Count}."); } return options; } - internal void ApplySettingsFromSnapshot(bool isDevMode, string? devPluginPath) + internal void ApplySettingsFromSnapshot(bool isDevMode, string? devAirAppPath) { if (isDevMode && !IsDevMode) { IsDevMode = true; } - if (!string.IsNullOrWhiteSpace(devPluginPath) && string.IsNullOrWhiteSpace(DevPluginPath)) + if (!string.IsNullOrWhiteSpace(devAirAppPath) && string.IsNullOrWhiteSpace(DevPluginPath)) { - DevPluginPath = devPluginPath; + DevPluginPath = devAirAppPath; } var allPaths = new List(DevPluginPaths); - if (!string.IsNullOrWhiteSpace(devPluginPath)) + if (!string.IsNullOrWhiteSpace(devAirAppPath)) { - foreach (var path in ResolveDevPluginPaths(devPluginPath)) + foreach (var path in ResolveDevPluginPaths(devAirAppPath)) { if (!allPaths.Contains(path, StringComparer.OrdinalIgnoreCase)) { @@ -104,12 +104,12 @@ public sealed class DevPluginOptions } else { - AppLogger.Warn("DevPlugin", $"Developer plugin path '{path}' does not exist. It will be skipped."); + AppLogger.Warn("DevAirApp", $"Developer plugin path '{path}' does not exist. It will be skipped."); } } catch (Exception ex) { - AppLogger.Warn("DevPlugin", $"Failed to resolve developer plugin path '{path}': {ex.Message}"); + AppLogger.Warn("DevAirApp", $"Failed to resolve developer plugin path '{path}': {ex.Message}"); } } diff --git a/desktop/LanMountainDesktop/plugins/LoadedPlugin.cs b/desktop/LanMountainDesktop/AirApps/LoadedAirApp.cs similarity index 61% rename from desktop/LanMountainDesktop/plugins/LoadedPlugin.cs rename to desktop/LanMountainDesktop/AirApps/LoadedAirApp.cs index c1bf965..a19960e 100644 --- a/desktop/LanMountainDesktop/plugins/LoadedPlugin.cs +++ b/desktop/LanMountainDesktop/AirApps/LoadedAirApp.cs @@ -4,36 +4,36 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using Microsoft.Extensions.Hosting; -namespace LanMountainDesktop.Plugins; +namespace LanMountainDesktop.AirApps; -public sealed class LoadedPlugin : IDisposable, IAsyncDisposable +public sealed class LoadedAirApp : IDisposable, IAsyncDisposable { private int _disposed; - internal LoadedPlugin( - PluginManifest manifest, + internal LoadedAirApp( + AirAppManifest manifest, string sourcePath, string assemblyPath, Assembly assembly, - IPlugin plugin, - IPluginRuntimeContext runtimeContext, + IAirApp plugin, + IAirAppRuntimeContext runtimeContext, IServiceProvider services, - IReadOnlyList settingsSections, - IReadOnlyList desktopComponents, - IReadOnlyList desktopComponentEditors, - IReadOnlyList exportedServices, - IReadOnlyList publicIpcServices, + IReadOnlyList settingsSections, + IReadOnlyList desktopComponents, + IReadOnlyList desktopComponentEditors, + IReadOnlyList exportedServices, + IReadOnlyList publicIpcServices, IReadOnlyList hostedServices, - PluginLoadContext loadContext) + AirAppLoadContext loadContext) { Manifest = manifest; SourcePath = sourcePath; AssemblyPath = assemblyPath; Assembly = assembly; - Plugin = plugin; + AirApp = plugin; RuntimeContext = runtimeContext; Services = services; SettingsSections = settingsSections; @@ -45,7 +45,7 @@ public sealed class LoadedPlugin : IDisposable, IAsyncDisposable LoadContext = loadContext; } - public PluginManifest Manifest { get; } + public AirAppManifest Manifest { get; } public string SourcePath { get; } @@ -53,25 +53,25 @@ public sealed class LoadedPlugin : IDisposable, IAsyncDisposable public Assembly Assembly { get; } - public IPlugin Plugin { get; } + public IAirApp AirApp { get; } - public IPluginRuntimeContext RuntimeContext { get; } + public IAirAppRuntimeContext RuntimeContext { get; } - public IPluginRuntimeContext Context => RuntimeContext; + public IAirAppRuntimeContext Context => RuntimeContext; public IServiceProvider Services { get; } - public IReadOnlyList SettingsSections { get; } + public IReadOnlyList SettingsSections { get; } - public IReadOnlyList DesktopComponents { get; } + public IReadOnlyList DesktopComponents { get; } - public IReadOnlyList DesktopComponentEditors { get; } + public IReadOnlyList DesktopComponentEditors { get; } - public IReadOnlyList ExportedServices { get; } + public IReadOnlyList ExportedServices { get; } - public IReadOnlyList PublicIpcServices { get; } + public IReadOnlyList PublicIpcServices { get; } - public PluginLoadContext LoadContext { get; } + public AirAppLoadContext LoadContext { get; } private IReadOnlyList HostedServices { get; } @@ -99,11 +99,19 @@ public sealed class LoadedPlugin : IDisposable, IAsyncDisposable } } - if (Plugin is IAsyncDisposable asyncDisposable) + try + { + await AirApp.OnStoppingAsync(); + } + catch + { + // Ignore AirApp stopping failures to allow unload cleanup. + } + + if (AirApp is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(); - } - else if (Plugin is IDisposable disposable) + } else if (AirApp is IDisposable disposable) { disposable.Dispose(); } diff --git a/desktop/LanMountainDesktop/plugins/README.md b/desktop/LanMountainDesktop/AirApps/README.md similarity index 100% rename from desktop/LanMountainDesktop/plugins/README.md rename to desktop/LanMountainDesktop/AirApps/README.md diff --git a/desktop/LanMountainDesktop/App.axaml.cs b/desktop/LanMountainDesktop/App.axaml.cs index a7a6f92..66a89c8 100644 --- a/desktop/LanMountainDesktop/App.axaml.cs +++ b/desktop/LanMountainDesktop/App.axaml.cs @@ -19,7 +19,7 @@ using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.DesktopHost; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.Abstractions; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.ExternalIpc; using LanMountainDesktop.Services.Loading; @@ -75,7 +75,7 @@ public partial class App : Application private DesktopTrayService? _desktopTrayService; private DispatcherTimer? _shellRecoveryTimer; - private PluginRuntimeService? _pluginRuntimeService; + private AirAppRuntimeService? _pluginRuntimeService; private MainWindow? _mainWindow; private FusedDesktopComponentLibraryWindow? _fusedComponentLibraryWindow; private bool _mainWindowClosed; @@ -103,7 +103,7 @@ public partial class App : Application CurrentPrivacyPolicyViewRequested?.Invoke(); } - public PluginRuntimeService? PluginRuntimeService => _pluginRuntimeService; + public AirAppRuntimeService? AirAppRuntimeService => _pluginRuntimeService; public ISettingsFacadeService SettingsFacade => _settingsFacade; public IHostApplicationLifecycle HostApplicationLifecycle => _hostApplicationLifecycle; internal ISettingsWindowService? SettingsWindowService => _settingsWindowService; @@ -158,7 +158,7 @@ public partial class App : Application if (e.Property == ActualThemeVariantProperty) { // 系统主题变化时,检查是否需要更新 - var themeMode = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App).ThemeMode; + var themeMode = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App).ThemeMode; if (string.Equals(themeMode, ThemeAppearanceValues.ThemeModeFollowSystem, StringComparison.OrdinalIgnoreCase)) { var newThemeVariant = (ThemeVariant?)e.NewValue; @@ -389,7 +389,7 @@ public partial class App : Application { _desktopShellInitializationStarted = true; _desktopShellHost ??= new DesktopShellHost( - InitializePluginRuntime, + InitializeAirAppRuntime, InitializeTrayIcon, desktop => { @@ -558,23 +558,23 @@ public partial class App : Application private void DisableAvaloniaDataAnnotationValidation() { - // Avalonia 12 中 BindingPlugins 已移除,数据验证插件不再需要手动禁用 + // Avalonia 12 中 BindingAirApps 已移除,数据验证插件不再需要手动禁用 // 编译型绑定默认开启,数据注解验证行为已改变 } - private void InitializePluginRuntime() + private void InitializeAirAppRuntime() { - ReportStartupProgress(StartupStage.LoadingPlugins, 30, "姝e湪鍔犺浇鎻掍欢..."); + ReportStartupProgress(StartupStage.LoadingAirApps, 30, "姝e湪鍔犺浇鎻掍欢..."); try { _pluginRuntimeService?.Dispose(); - _pluginRuntimeService = new PluginRuntimeService(_settingsFacade, _publicIpcHostService); - HostSettingsFacadeProvider.BindPluginRuntime(_pluginRuntimeService); - _pluginRuntimeService.LoadInstalledPlugins(); + _pluginRuntimeService = new AirAppRuntimeService(_settingsFacade, _publicIpcHostService); + HostSettingsFacadeProvider.BindAirAppRuntime(_pluginRuntimeService); + _pluginRuntimeService.LoadInstalledAirApps(); } catch (Exception ex) { - AppLogger.Warn("PluginRuntime", "Failed to initialize plugin runtime.", ex); + AppLogger.Warn("AirAppRuntime", "Failed to initialize plugin runtime.", ex); } } @@ -730,7 +730,7 @@ public partial class App : Application return false; } - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); return appSnapshot.EnableFusedDesktop; } @@ -784,7 +784,7 @@ public partial class App : Application private void ApplyThemeFromSettings() { var snapshot = _appearanceThemeService.GetCurrent(); - var themeMode = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App).ThemeMode; + var themeMode = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App).ThemeMode; // 处理跟随系统主题模式 if (string.Equals(themeMode, ThemeAppearanceValues.ThemeModeFollowSystem, StringComparison.OrdinalIgnoreCase)) @@ -813,7 +813,7 @@ public partial class App : Application private void ApplyCurrentCultureFromSettings() { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var languageCode = _localizationService.NormalizeLanguageCode(snapshot.LanguageCode); CultureInfo culture; @@ -1027,7 +1027,7 @@ public partial class App : Application { _ = sender; - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } @@ -1188,7 +1188,7 @@ public partial class App : Application } catch (Exception ex) { - AppLogger.Warn("PluginRuntime", "Failed to dispose plugin runtime during shutdown.", ex); + AppLogger.Warn("AirAppRuntime", "Failed to dispose plugin runtime during shutdown.", ex); } finally { @@ -1576,13 +1576,13 @@ public partial class App : Application private bool ShouldShowMainWindowInTaskbar() { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); return snapshot.ShowInTaskbar && !snapshot.EnableMainWindowDesktopLayer; } private bool IsMainWindowDesktopLayerEnabled() { - return _settingsFacade.Settings.LoadSnapshot(SettingsScope.App).EnableMainWindowDesktopLayer; + return _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App).EnableMainWindowDesktopLayer; } private void ActivateOrRefreshMainWindowLayer(MainWindow mainWindow, string source) @@ -1624,7 +1624,7 @@ public partial class App : Application private void ApplyFusedDesktopRuntimeState() { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); try { if (snapshot.EnableFusedDesktop) @@ -1738,7 +1738,7 @@ public partial class App : Application private string L(string key, string fallback) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var languageCode = _localizationService.NormalizeLanguageCode(snapshot.LanguageCode); return _localizationService.GetString(languageCode, key, fallback); } diff --git a/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentEditorRegistry.cs b/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentEditorRegistry.cs index 1019739..1657ed4 100644 --- a/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentEditorRegistry.cs +++ b/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentEditorRegistry.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using Avalonia.Controls; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; diff --git a/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentRuntimeContext.cs b/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentRuntimeContext.cs index df73f22..55763ec 100644 --- a/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentRuntimeContext.cs +++ b/desktop/LanMountainDesktop/ComponentSystem/DesktopComponentRuntimeContext.cs @@ -1,5 +1,5 @@ -using LanMountainDesktop.Host.Abstractions; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -11,7 +11,7 @@ public sealed record DesktopComponentRuntimeContext( ISettingsFacadeService SettingsFacade, ISettingsService SettingsService, IAppearanceThemeService AppearanceTheme, - ComponentChromeContext Chrome, + AirAppComponentChromeContext Chrome, IComponentSettingsAccessor ComponentSettingsAccessor, IComponentInstanceSettingsStore ComponentSettingsStore, DesktopComponentRenderMode RenderMode = DesktopComponentRenderMode.Live); diff --git a/desktop/LanMountainDesktop/ComponentSystem/IComponentChromeContextAware.cs b/desktop/LanMountainDesktop/ComponentSystem/IComponentChromeContextAware.cs index 4f3ef7c..944936a 100644 --- a/desktop/LanMountainDesktop/ComponentSystem/IComponentChromeContextAware.cs +++ b/desktop/LanMountainDesktop/ComponentSystem/IComponentChromeContextAware.cs @@ -1,8 +1,8 @@ -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.ComponentSystem; -public interface IComponentChromeContextAware +public interface IAirAppComponentChromeContextAware { - void SetComponentChromeContext(ComponentChromeContext context); + void SetAirAppComponentChromeContext(AirAppComponentChromeContext context); } diff --git a/desktop/LanMountainDesktop/ComponentSystem/IComponentSettingsContextAware.cs b/desktop/LanMountainDesktop/ComponentSystem/IComponentSettingsContextAware.cs index 6fc03a6..7c8e2dd 100644 --- a/desktop/LanMountainDesktop/ComponentSystem/IComponentSettingsContextAware.cs +++ b/desktop/LanMountainDesktop/ComponentSystem/IComponentSettingsContextAware.cs @@ -1,4 +1,4 @@ -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; diff --git a/desktop/LanMountainDesktop/DesktopShellHost.cs b/desktop/LanMountainDesktop/DesktopShellHost.cs index aeadc83..0f34d06 100644 --- a/desktop/LanMountainDesktop/DesktopShellHost.cs +++ b/desktop/LanMountainDesktop/DesktopShellHost.cs @@ -2,13 +2,13 @@ using System; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.DesktopHost; public sealed class DesktopShellHost : IDesktopShellHost { - private readonly Action _initializePluginRuntime; + private readonly Action _initializeAirAppRuntime; private readonly Action _initializeTrayIcon; private readonly Action _createAndAssignMainWindow; private readonly Action _performExitCleanup; @@ -16,14 +16,14 @@ public sealed class DesktopShellHost : IDesktopShellHost private readonly Action _startWeatherRefresh; public DesktopShellHost( - Action initializePluginRuntime, + Action initializeAirAppRuntime, Action initializeTrayIcon, Action createAndAssignMainWindow, Action performExitCleanup, Action startActivationListener, Action startWeatherRefresh) { - _initializePluginRuntime = initializePluginRuntime; + _initializeAirAppRuntime = initializeAirAppRuntime; _initializeTrayIcon = initializeTrayIcon; _createAndAssignMainWindow = createAndAssignMainWindow; _performExitCleanup = performExitCleanup; @@ -40,7 +40,7 @@ public sealed class DesktopShellHost : IDesktopShellHost { ArgumentNullException.ThrowIfNull(application); - _initializePluginRuntime(); + _initializeAirAppRuntime(); _initializeTrayIcon(); if (application.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) diff --git a/desktop/LanMountainDesktop/Helpers/PluginCatalogMarkdownHelper.cs b/desktop/LanMountainDesktop/Helpers/AirAppCatalogMarkdownHelper.cs similarity index 95% rename from desktop/LanMountainDesktop/Helpers/PluginCatalogMarkdownHelper.cs rename to desktop/LanMountainDesktop/Helpers/AirAppCatalogMarkdownHelper.cs index 6c26f8f..9f79e46 100644 --- a/desktop/LanMountainDesktop/Helpers/PluginCatalogMarkdownHelper.cs +++ b/desktop/LanMountainDesktop/Helpers/AirAppCatalogMarkdownHelper.cs @@ -6,7 +6,7 @@ using Markdown.Avalonia; namespace LanMountainDesktop.Helpers; -public static class PluginCatalogMarkdownHelper +public static class AirAppCatalogMarkdownHelper { private static Markdown.Avalonia.Markdown? _engine; diff --git a/desktop/LanMountainDesktop/LanMountainDesktop.csproj b/desktop/LanMountainDesktop/LanMountainDesktop.csproj index 0ef8d4e..74323c9 100644 --- a/desktop/LanMountainDesktop/LanMountainDesktop.csproj +++ b/desktop/LanMountainDesktop/LanMountainDesktop.csproj @@ -32,7 +32,7 @@ - + diff --git a/desktop/LanMountainDesktop/Models/AppSettingsSnapshot.cs b/desktop/LanMountainDesktop/Models/AppSettingsSnapshot.cs index ee7af8c..87d1d2a 100644 --- a/desktop/LanMountainDesktop/Models/AppSettingsSnapshot.cs +++ b/desktop/LanMountainDesktop/Models/AppSettingsSnapshot.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts.Launcher; namespace LanMountainDesktop.Models; diff --git a/desktop/LanMountainDesktop/Program.cs b/desktop/LanMountainDesktop/Program.cs index b0f5dcc..414a433 100644 --- a/desktop/LanMountainDesktop/Program.cs +++ b/desktop/LanMountainDesktop/Program.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Avalonia; using LanMountainDesktop.DesktopHost; using LanMountainDesktop.Models; -using LanMountainDesktop.Plugins; +using LanMountainDesktop.AirApps; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -24,7 +24,7 @@ public sealed class Program { AppLogger.Initialize(); AppDataPathProvider.Initialize(args); - DevPluginOptions.Parse(args); + DevAirAppOptions.Parse(args); RegisterGlobalExceptionLogging(); DesktopBootstrap.InitializeStartupServices( @@ -130,7 +130,7 @@ public sealed class Program { var snapshot = HostSettingsFacadeProvider.GetOrCreate() .Settings - .LoadSnapshot(LanMountainDesktop.PluginSdk.SettingsScope.App); + .LoadSnapshot(LanMountainDesktop.AirAppSdk.AirAppSettingsScope.App); return AppRenderingModeHelper.Normalize(snapshot.AppRenderMode); } catch (Exception ex) @@ -146,7 +146,7 @@ public sealed class Program { var snapshot = HostSettingsFacadeProvider.GetOrCreate() .Settings - .LoadSnapshot(LanMountainDesktop.PluginSdk.SettingsScope.App); + .LoadSnapshot(LanMountainDesktop.AirAppSdk.AirAppSettingsScope.App); if (OperatingSystem.IsWindows()) { LanMountainDesktop.Platform.Windows.ChromePatchState.UseSystemChrome = snapshot.UseSystemChrome; diff --git a/desktop/LanMountainDesktop/Services/PluginAppearanceSnapshotMapper.cs b/desktop/LanMountainDesktop/Services/AirAppAppearanceSnapshotMapper.cs similarity index 87% rename from desktop/LanMountainDesktop/Services/PluginAppearanceSnapshotMapper.cs rename to desktop/LanMountainDesktop/Services/AirAppAppearanceSnapshotMapper.cs index 3936c01..79ea7db 100644 --- a/desktop/LanMountainDesktop/Services/PluginAppearanceSnapshotMapper.cs +++ b/desktop/LanMountainDesktop/Services/AirAppAppearanceSnapshotMapper.cs @@ -3,21 +3,21 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Media; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; -internal static class PluginAppearanceSnapshotMapper +internal static class AirAppAppearanceSnapshotMapper { /// /// Normal host-to-plugin appearance mapping for the live material color pipeline. /// - public static PluginAppearanceSnapshot FromMaterialColorSnapshot(MaterialColorSnapshot snapshot) + public static AirAppAppearanceSnapshot FromMaterialColorSnapshot(MaterialColorSnapshot snapshot) { ArgumentNullException.ThrowIfNull(snapshot); - return new PluginAppearanceSnapshot( - PluginCornerRadiusTokens.FromShared(snapshot.CornerRadiusTokens), + return new AirAppAppearanceSnapshot( + AirAppCornerRadiusTokens.FromShared(snapshot.CornerRadiusTokens), snapshot.IsNightMode ? "Dark" : "Light", ToText(snapshot.AccentColor), ToText(snapshot.EffectiveSeedColor), @@ -26,7 +26,7 @@ internal static class PluginAppearanceSnapshotMapper BuildColorRoles(snapshot), snapshot.Surfaces.ToDictionary( pair => pair.Key.ToString(), - pair => new PluginMaterialSurfaceSnapshot( + pair => new AirAppMaterialSurfaceSnapshot( ToText(pair.Value.BackgroundColor), ToText(pair.Value.BorderColor), pair.Value.BlurRadius, @@ -39,12 +39,12 @@ internal static class PluginAppearanceSnapshotMapper /// Compatibility-only mapper for older hosts that still expose /// instead of the material color pipeline. /// - public static PluginAppearanceSnapshot FromCompatibilityAppearanceSnapshot(AppearanceThemeSnapshot snapshot) + public static AirAppAppearanceSnapshot FromCompatibilityAppearanceSnapshot(AppearanceThemeSnapshot snapshot) { ArgumentNullException.ThrowIfNull(snapshot); - return new PluginAppearanceSnapshot( - PluginCornerRadiusTokens.FromShared(snapshot.CornerRadiusTokens), + return new AirAppAppearanceSnapshot( + AirAppCornerRadiusTokens.FromShared(snapshot.CornerRadiusTokens), snapshot.IsNightMode ? "Dark" : "Light", ToText(snapshot.AccentColor), ToText(snapshot.EffectiveSeedColor), @@ -67,7 +67,7 @@ internal static class PluginAppearanceSnapshotMapper /// Backward-compatible alias for older call sites. Prefer . /// [Obsolete("Use FromCompatibilityAppearanceSnapshot instead.")] - public static PluginAppearanceSnapshot FromAppearanceSnapshot(AppearanceThemeSnapshot snapshot) + public static AirAppAppearanceSnapshot FromAppearanceSnapshot(AppearanceThemeSnapshot snapshot) { return FromCompatibilityAppearanceSnapshot(snapshot); } diff --git a/desktop/LanMountainDesktop/Services/PluginInstallTargetAccess.cs b/desktop/LanMountainDesktop/Services/AirAppInstallTargetAccess.cs similarity index 92% rename from desktop/LanMountainDesktop/Services/PluginInstallTargetAccess.cs rename to desktop/LanMountainDesktop/Services/AirAppInstallTargetAccess.cs index 33fe723..d0af4de 100644 --- a/desktop/LanMountainDesktop/Services/PluginInstallTargetAccess.cs +++ b/desktop/LanMountainDesktop/Services/AirAppInstallTargetAccess.cs @@ -3,7 +3,7 @@ using System.IO; namespace LanMountainDesktop.Services; -internal static class PluginInstallTargetAccess +internal static class AirAppInstallTargetAccess { public static bool CanWriteDirectory(string directory) { diff --git a/desktop/LanMountainDesktop/Services/AirAppLauncherService.cs b/desktop/LanMountainDesktop/Services/AirAppLauncherService.cs index ce3a687..628f258 100644 --- a/desktop/LanMountainDesktop/Services/AirAppLauncherService.cs +++ b/desktop/LanMountainDesktop/Services/AirAppLauncherService.cs @@ -18,6 +18,8 @@ public interface IAirAppLauncherService void OpenWhiteboard(string componentId, string? sourcePlacementId); void OpenRssReader(string componentId, string? sourcePlacementId, string? targetEntryId = null); + + void OpenThirdPartyAirAppWindow(string appId, string windowId, string packageDirectory, string? sourceComponentId, string? sourcePlacementId); } internal sealed class AirAppLauncherService : IAirAppLauncherService @@ -63,19 +65,30 @@ internal sealed class AirAppLauncherService : IAirAppLauncherService _ = OpenAsync(RssReaderAppId, componentId, sourcePlacementId, targetEntryId); } + public void OpenThirdPartyAirAppWindow(string appId, string windowId, string packageDirectory, string? sourceComponentId, string? sourcePlacementId) + { + ArgumentException.ThrowIfNullOrWhiteSpace(appId); + ArgumentException.ThrowIfNullOrWhiteSpace(windowId); + ArgumentException.ThrowIfNullOrWhiteSpace(packageDirectory); + + _ = OpenAsync(appId, sourceComponentId, sourcePlacementId, windowId, packageDirectory); + } + internal static AirAppOpenRequest BuildOpenRequest( string appId, string? sourceComponentId, string? sourcePlacementId, int requesterProcessId, - string? targetEntryId = null) + string? targetEntryId = null, + string? appPackagePath = null) { return new AirAppOpenRequest( appId.Trim(), string.IsNullOrWhiteSpace(sourceComponentId) ? null : sourceComponentId.Trim(), string.IsNullOrWhiteSpace(sourcePlacementId) ? null : sourcePlacementId.Trim(), requesterProcessId, - string.IsNullOrWhiteSpace(targetEntryId) ? null : targetEntryId.Trim()); + string.IsNullOrWhiteSpace(targetEntryId) ? null : targetEntryId.Trim(), + string.IsNullOrWhiteSpace(appPackagePath) ? null : Path.GetFullPath(appPackagePath)); } internal static string BuildSingleInstanceKey(string appId, string? sourceComponentId, string? sourcePlacementId) @@ -95,9 +108,9 @@ internal sealed class AirAppLauncherService : IAirAppLauncherService return $"{normalizedAppId}:{normalizedComponentId}:{normalizedPlacementId}"; } - private static async Task OpenAsync(string appId, string sourceComponentId, string? sourcePlacementId, string? targetEntryId = null) + private static async Task OpenAsync(string appId, string sourceComponentId, string? sourcePlacementId, string? targetEntryId = null, string? appPackagePath = null) { - var request = BuildOpenRequest(appId, sourceComponentId, sourcePlacementId, Environment.ProcessId, targetEntryId); + var request = BuildOpenRequest(appId, sourceComponentId, sourcePlacementId, Environment.ProcessId, targetEntryId, appPackagePath); try { var result = await SendOpenRequestAsync(request).ConfigureAwait(false); diff --git a/desktop/LanMountainDesktop/Services/AppDataPathProvider.cs b/desktop/LanMountainDesktop/Services/AppDataPathProvider.cs index 59e2d1f..f93fb86 100644 --- a/desktop/LanMountainDesktop/Services/AppDataPathProvider.cs +++ b/desktop/LanMountainDesktop/Services/AppDataPathProvider.cs @@ -40,9 +40,9 @@ public static class AppDataPathProvider return GetDataRoot(); } - public static string GetPluginMarketDirectory() + public static string GetAirAppMarketDirectory() { - return Path.Combine(GetDataRoot(), "PluginMarket"); + return Path.Combine(GetDataRoot(), "AirAppMarket"); } public static string GetWallpapersDirectory() diff --git a/desktop/LanMountainDesktop/Services/AppRestartService.cs b/desktop/LanMountainDesktop/Services/AppRestartService.cs index cc054d2..ff993f4 100644 --- a/desktop/LanMountainDesktop/Services/AppRestartService.cs +++ b/desktop/LanMountainDesktop/Services/AppRestartService.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using System.Reflection; using System.Text; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts.Launcher; namespace LanMountainDesktop.Services; diff --git a/desktop/LanMountainDesktop/Services/AppearanceThemeService.cs b/desktop/LanMountainDesktop/Services/AppearanceThemeService.cs index 83f975a..8fea818 100644 --- a/desktop/LanMountainDesktop/Services/AppearanceThemeService.cs +++ b/desktop/LanMountainDesktop/Services/AppearanceThemeService.cs @@ -12,11 +12,11 @@ using Avalonia.Media; using Avalonia.Styling; using Avalonia.Threading; using Avalonia.Media.Imaging; -using LanMountainDesktop.Appearance; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts; using LanMountainDesktop.Theme; using Microsoft.Win32; diff --git a/desktop/LanMountainDesktop/Services/ComponentEditorWindowService.cs b/desktop/LanMountainDesktop/Services/ComponentEditorWindowService.cs index 518f62d..116685f 100644 --- a/desktop/LanMountainDesktop/Services/ComponentEditorWindowService.cs +++ b/desktop/LanMountainDesktop/Services/ComponentEditorWindowService.cs @@ -2,7 +2,7 @@ using System; using Avalonia.Controls; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Views; diff --git a/desktop/LanMountainDesktop/Services/ComponentSettingsService.cs b/desktop/LanMountainDesktop/Services/ComponentSettingsService.cs index 92b1107..e7e6115 100644 --- a/desktop/LanMountainDesktop/Services/ComponentSettingsService.cs +++ b/desktop/LanMountainDesktop/Services/ComponentSettingsService.cs @@ -1,7 +1,7 @@ using System; using System.Reflection; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; namespace LanMountainDesktop.Services; @@ -47,7 +47,7 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore if (_settingsService is not null) { return _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, subjectId: string.Empty, placementId: null); } @@ -66,7 +66,7 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore if (_settingsService is not null) { _settingsService.SaveSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, snapshot ?? new ComponentSettingsSnapshot(), subjectId: string.Empty, placementId: null); @@ -81,7 +81,7 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore if (_settingsService is not null) { return _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, subjectId: componentId, placementId: placementId); } @@ -94,7 +94,7 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore if (_settingsService is not null) { _settingsService.SaveSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, snapshot ?? new ComponentSettingsSnapshot(), subjectId: componentId, placementId: placementId); @@ -111,23 +111,23 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore if (_settingsService is not null) { _settingsService.SaveSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, new ComponentSettingsSnapshot(), subjectId: componentId, placementId: placementId); - _settingsService.DeleteSection(SettingsScope.ComponentInstance, componentId, LegacySectionId, placementId); + _settingsService.DeleteSection(AirAppSettingsScope.ComponentInstance, componentId, LegacySectionId, placementId); return; } _stateStore?.DeleteState(componentId, placementId); } - public T LoadPluginSettings(string componentId, string? placementId) where T : new() + public T LoadAirAppSettings(string componentId, string? placementId) where T : new() { if (_settingsService is not null) { return _settingsService.LoadSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, subjectId: componentId, sectionId: LegacySectionId, placementId: placementId); @@ -141,12 +141,12 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore return new T(); } - public void SavePluginSettings(string componentId, string? placementId, T settings) + public void SaveAirAppSettings(string componentId, string? placementId, T settings) { if (_settingsService is not null) { _settingsService.SaveSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, subjectId: componentId, sectionId: LegacySectionId, section: settings, @@ -160,12 +160,12 @@ public sealed class ComponentSettingsService : IComponentInstanceSettingsStore } } - public void DeletePluginSettings(string componentId, string? placementId) + public void DeleteAirAppSettings(string componentId, string? placementId) { if (_settingsService is not null) { _settingsService.DeleteSection( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, subjectId: componentId, sectionId: LegacySectionId, placementId: placementId); diff --git a/desktop/LanMountainDesktop/Services/DataStorageService.cs b/desktop/LanMountainDesktop/Services/DataStorageService.cs index fe8c3cb..23ff1e8 100644 --- a/desktop/LanMountainDesktop/Services/DataStorageService.cs +++ b/desktop/LanMountainDesktop/Services/DataStorageService.cs @@ -36,7 +36,7 @@ public sealed class DataStorageService [ "Whiteboards", "Extensions", - "PluginMarket", + "AirAppMarket", "Wallpapers" ]; @@ -44,8 +44,8 @@ public sealed class DataStorageService { new("logs", "日志文件", "应用运行日志", "", true, "#9E9E9E"), new("whiteboards", "白板笔记", "桌面白板笔记数据", "Whiteboards", true, "#FF9800"), - new("plugins", "插件数据", "已安装插件文件", "Extensions/Plugins", true, "#2196F3"), - new("market", "插件市场缓存", "插件市场元数据缓存", "PluginMarket", true, "#9C27B0"), + new("plugins", "插件数据", "已安装插件文件", "Extensions/AirApps", true, "#2196F3"), + new("market", "插件市场缓存", "插件市场元数据缓存", "AirAppMarket", true, "#9C27B0"), new("wallpapers", "壁纸文件", "下载的壁纸资源", "Wallpapers", true, "#E91E63"), new("settings", "设置文件", "应用配置数据", "", false, "#4CAF50") }; diff --git a/desktop/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs b/desktop/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs index 9ee1ed1..cb10f21 100644 --- a/desktop/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs +++ b/desktop/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs @@ -5,8 +5,8 @@ using System.Reflection; using Avalonia.Controls; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.Plugins; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirApps; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Views.ComponentEditors; namespace LanMountainDesktop.Services; @@ -15,7 +15,7 @@ public static class DesktopComponentEditorRegistryFactory { public static DesktopComponentEditorRegistry Create( ComponentRegistry componentRegistry, - PluginRuntimeService? pluginRuntimeService) + AirAppRuntimeService? pluginRuntimeService) { ArgumentNullException.ThrowIfNull(componentRegistry); @@ -38,7 +38,7 @@ public static class DesktopComponentEditorRegistryFactory registrations.Add(new DesktopComponentEditorRegistration( registration.ComponentId, - context => CreatePluginEditor(contribution, context), + context => CreateAirAppEditor(contribution, context), registration.PreferredWidth, registration.PreferredHeight, registration.MinScale, @@ -372,26 +372,26 @@ public static class DesktopComponentEditorRegistryFactory })); } - private static Control CreatePluginEditor( - PluginDesktopComponentEditorContribution contribution, + private static Control CreateAirAppEditor( + AirAppDesktopComponentEditorContribution contribution, DesktopComponentEditorContext context) { - var settingsService = contribution.Plugin.Services.GetService(typeof(ISettingsService)) as ISettingsService + var settingsService = contribution.AirApp.Services.GetService(typeof(ISettingsService)) as ISettingsService ?? context.SettingsService; - var pluginSettings = new PluginScopedSettingsService( - contribution.Plugin.Manifest.Id, + var pluginSettings = new AirAppScopedSettingsService( + contribution.AirApp.Manifest.Id, settingsService); - var pluginContext = new PluginDesktopComponentEditorContext( - contribution.Plugin.Manifest, - contribution.Plugin.Context.PluginDirectory, - contribution.Plugin.Context.DataDirectory, - contribution.Plugin.Services, - contribution.Plugin.Context.Properties, + var pluginContext = new AirAppComponentEditorContext( + contribution.AirApp.Manifest, + contribution.AirApp.Context.AirAppDirectory, + contribution.AirApp.Context.DataDirectory, + contribution.AirApp.Services, + contribution.AirApp.Context.Properties, context.ComponentId, context.PlacementId, pluginSettings, context.HostContext); - return contribution.Registration.EditorFactory(contribution.Plugin.Services, pluginContext); + return contribution.Registration.EditorFactory(contribution.AirApp.Services, pluginContext); } } diff --git a/desktop/LanMountainDesktop/Services/DesktopComponentRegistryFactory.cs b/desktop/LanMountainDesktop/Services/DesktopComponentRegistryFactory.cs index 170064f..038728c 100644 --- a/desktop/LanMountainDesktop/Services/DesktopComponentRegistryFactory.cs +++ b/desktop/LanMountainDesktop/Services/DesktopComponentRegistryFactory.cs @@ -9,8 +9,8 @@ using Avalonia.Layout; using Avalonia.Media; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.ComponentSystem.Extensions; -using LanMountainDesktop.Host.Abstractions; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Views.Components; @@ -18,7 +18,7 @@ namespace LanMountainDesktop.Services; public static class DesktopComponentRegistryFactory { - public static ComponentRegistry Create(PluginRuntimeService? pluginRuntimeService) + public static ComponentRegistry Create(AirAppRuntimeService? pluginRuntimeService) { var registry = ComponentRegistry .CreateDefault() @@ -26,7 +26,7 @@ public static class DesktopComponentRegistryFactory JsonComponentExtensionProvider.LoadProvidersFromDirectory( Path.Combine(AppContext.BaseDirectory, "Extensions", "Components"))); - var pluginDefinitions = GetPluginDefinitions(registry, pluginRuntimeService); + var pluginDefinitions = GetAirAppDefinitions(registry, pluginRuntimeService); return pluginDefinitions.Count == 0 ? registry : registry.RegisterComponents(pluginDefinitions); @@ -34,7 +34,7 @@ public static class DesktopComponentRegistryFactory public static DesktopComponentRuntimeRegistry CreateRuntimeRegistry( ComponentRegistry componentRegistry, - PluginRuntimeService? pluginRuntimeService, + AirAppRuntimeService? pluginRuntimeService, ISettingsFacadeService settingsFacade, IMaterialColorService? materialColorService = null) { @@ -57,17 +57,17 @@ public static class DesktopComponentRegistryFactory if (!registeredIds.Add(registration.ComponentId)) { Debug.WriteLine( - $"[PluginRuntime] Skipped plugin widget '{registration.ComponentId}' from '{contribution.Plugin.Manifest.Id}' because a runtime registration already exists."); + $"[AirAppRuntime] Skipped plugin widget '{registration.ComponentId}' from '{contribution.AirApp.Manifest.Id}' because a runtime registration already exists."); continue; } registrations.Add(new DesktopComponentRuntimeRegistration( registration.ComponentId, registration.DisplayNameLocalizationKey, - factoryContext => CreatePluginControl(contribution, factoryContext, resolvedMaterialColorService), + factoryContext => CreateAirAppControl(contribution, factoryContext, resolvedMaterialColorService), chromeContext => { - var appearanceContext = CreatePluginAppearanceContext(chromeContext); + var appearanceContext = CreateAirAppAppearanceContext(chromeContext); return registration.ResolveCornerRadius(appearanceContext, chromeContext.CellSize); })); } @@ -77,9 +77,9 @@ public static class DesktopComponentRegistryFactory return new DesktopComponentRuntimeRegistry(componentRegistry, registrations); } - private static List GetPluginDefinitions( + private static List GetAirAppDefinitions( ComponentRegistry baseRegistry, - PluginRuntimeService? pluginRuntimeService) + AirAppRuntimeService? pluginRuntimeService) { var definitions = new List(); if (pluginRuntimeService is null) @@ -97,7 +97,7 @@ public static class DesktopComponentRegistryFactory if (!knownIds.Add(registration.ComponentId)) { Debug.WriteLine( - $"[PluginRuntime] Skipped plugin widget '{registration.ComponentId}' from '{contribution.Plugin.Manifest.Id}' because the component id already exists."); + $"[AirAppRuntime] Skipped plugin widget '{registration.ComponentId}' from '{contribution.AirApp.Manifest.Id}' because the component id already exists."); continue; } @@ -110,7 +110,7 @@ public static class DesktopComponentRegistryFactory registration.MinHeightCells, registration.AllowStatusBarPlacement, registration.AllowDesktopPlacement, - registration.ResizeMode == PluginDesktopComponentResizeMode.Free + registration.ResizeMode == AirAppComponentResizeMode.Free ? DesktopComponentResizeMode.Free : DesktopComponentResizeMode.Proportional, Description: registration.Description, @@ -120,52 +120,65 @@ public static class DesktopComponentRegistryFactory return definitions; } - private static Control CreatePluginControl( - PluginDesktopComponentContribution contribution, + private static Control CreateAirAppControl( + AirAppDesktopComponentContribution contribution, DesktopComponentControlFactoryContext context, IMaterialColorService materialColorService) { try { - var settingsService = contribution.Plugin.Services.GetService(typeof(ISettingsService)) as ISettingsService + var settingsService = contribution.AirApp.Services.GetService(typeof(ISettingsService)) as ISettingsService ?? context.SettingsService; - var pluginSettings = new PluginScopedSettingsService( - contribution.Plugin.Manifest.Id, + var pluginSettings = new AirAppScopedSettingsService( + contribution.AirApp.Manifest.Id, settingsService); - var pluginAppearance = new PluginAppearanceContext( - PluginAppearanceSnapshotMapper.FromMaterialColorSnapshot( + var pluginAppearance = new AirAppAppearanceContext( + AirAppAppearanceSnapshotMapper.FromMaterialColorSnapshot( materialColorService.GetMaterialColorSnapshot())); - var pluginContext = new PluginDesktopComponentContext( - contribution.Plugin.Manifest, - contribution.Plugin.Context.PluginDirectory, - contribution.Plugin.Context.DataDirectory, - contribution.Plugin.Services, - contribution.Plugin.Context.Properties, + var pluginContext = new AirAppComponentContext( + contribution.AirApp.Manifest, + contribution.AirApp.Context.AirAppDirectory, + contribution.AirApp.Context.DataDirectory, + contribution.AirApp.Services, + contribution.AirApp.Context.Properties, contribution.Registration.ComponentId, context.PlacementId, context.CellSize, pluginAppearance, - pluginSettings); + pluginSettings) + { + OpenWindowHandler = windowId => + { + var launcher = AirAppLauncherServiceProvider.GetOrCreate(); + launcher.OpenThirdPartyAirAppWindow( + contribution.AirApp.Manifest.Id, + windowId, + contribution.AirApp.Context.AirAppDirectory, + contribution.Registration.ComponentId, + context.PlacementId); + return Task.CompletedTask; + } + }; - return contribution.Registration.ControlFactory(contribution.Plugin.Services, pluginContext); + return contribution.Registration.ControlFactory(contribution.AirApp.Services, pluginContext); } catch (Exception ex) { Debug.WriteLine( - $"[PluginRuntime] Failed to create widget '{contribution.Registration.ComponentId}' from '{contribution.Plugin.Manifest.Id}': {ex}"); - return CreatePluginErrorControl(contribution, ex); + $"[AirAppRuntime] Failed to create widget '{contribution.Registration.ComponentId}' from '{contribution.AirApp.Manifest.Id}': {ex}"); + return CreateAirAppErrorControl(contribution, ex); } } - private static IPluginAppearanceContext CreatePluginAppearanceContext(ComponentChromeContext chromeContext) + private static IAirAppAppearanceContext CreateAirAppAppearanceContext(AirAppComponentChromeContext chromeContext) { - return new PluginAppearanceContext(new PluginAppearanceSnapshot( - CornerRadiusTokens: PluginCornerRadiusTokens.FromShared(chromeContext.CornerRadiusTokens), + return new AirAppAppearanceContext(new AirAppAppearanceSnapshot( + CornerRadiusTokens: AirAppCornerRadiusTokens.FromShared(chromeContext.CornerRadiusTokens), ThemeVariant: "Unknown")); } - private static Control CreatePluginErrorControl( - PluginDesktopComponentContribution contribution, + private static Control CreateAirAppErrorControl( + AirAppDesktopComponentContribution contribution, Exception exception) { return new Border @@ -189,7 +202,7 @@ public static class DesktopComponentRegistryFactory }, new TextBlock { - Text = $"Plugin {contribution.Plugin.Manifest.Name} failed to create this widget.", + Text = $"AirApp {contribution.AirApp.Manifest.Name} failed to create this widget.", TextWrapping = TextWrapping.Wrap }, new TextBlock diff --git a/desktop/LanMountainDesktop/Services/DesktopTrayService.cs b/desktop/LanMountainDesktop/Services/DesktopTrayService.cs index 138df62..b397db2 100644 --- a/desktop/LanMountainDesktop/Services/DesktopTrayService.cs +++ b/desktop/LanMountainDesktop/Services/DesktopTrayService.cs @@ -1,7 +1,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Threading; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; diff --git a/desktop/LanMountainDesktop/Services/ElevatedPluginInstallService.cs b/desktop/LanMountainDesktop/Services/ElevatedAirAppInstallService.cs similarity index 89% rename from desktop/LanMountainDesktop/Services/ElevatedPluginInstallService.cs rename to desktop/LanMountainDesktop/Services/ElevatedAirAppInstallService.cs index de3c520..e286194 100644 --- a/desktop/LanMountainDesktop/Services/ElevatedPluginInstallService.cs +++ b/desktop/LanMountainDesktop/Services/ElevatedAirAppInstallService.cs @@ -8,7 +8,7 @@ using LanMountainDesktop.Shared.Contracts.Launcher; namespace LanMountainDesktop.Services; -internal sealed record ElevatedPluginInstallResult( +internal sealed record ElevatedAirAppInstallResult( bool Success, string? Code, string? Message, @@ -17,9 +17,9 @@ internal sealed record ElevatedPluginInstallResult( string? ManifestId, string? ManifestName); -internal sealed class ElevatedPluginInstallService +internal sealed class ElevatedAirAppInstallService { - public async Task InstallAsync( + public async Task InstallAsync( string sourcePackagePath, string pluginsDirectory, CancellationToken cancellationToken) @@ -29,7 +29,7 @@ internal sealed class ElevatedPluginInstallService if (!OperatingSystem.IsWindows()) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "elevation_unsupported", "Elevated plugin installation is only supported on Windows.", @@ -42,7 +42,7 @@ internal sealed class ElevatedPluginInstallService var launcherPath = ResolveLauncherExecutablePath(); if (string.IsNullOrWhiteSpace(launcherPath) || !File.Exists(launcherPath)) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "launcher_not_found", "Launcher executable was not found for elevated plugin installation.", @@ -54,7 +54,7 @@ internal sealed class ElevatedPluginInstallService var resultPath = Path.Combine( Path.GetTempPath(), - $"LanMountainDesktop.PluginInstall.{Guid.NewGuid():N}.json"); + $"LanMountainDesktop.AirAppInstall.{Guid.NewGuid():N}.json"); try { @@ -84,7 +84,7 @@ internal sealed class ElevatedPluginInstallService var process = Process.Start(startInfo); if (process is null) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "launch_failed", "Elevated plugin installer did not start.", @@ -100,10 +100,10 @@ internal sealed class ElevatedPluginInstallService return ReadResult(resultPath); } - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( process.ExitCode == 0, process.ExitCode == 0 ? "ok" : "installer_failed", - process.ExitCode == 0 ? "Plugin installed." : $"Elevated installer exited with code {process.ExitCode}.", + process.ExitCode == 0 ? "AirApp installed." : $"Elevated installer exited with code {process.ExitCode}.", process.ExitCode == 0 ? null : $"Elevated installer exited with code {process.ExitCode}.", null, null, @@ -115,10 +115,10 @@ internal sealed class ElevatedPluginInstallService } catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "elevation_cancelled", - "Plugin installation was cancelled before elevation was approved.", + "AirApp installation was cancelled before elevation was approved.", ex.Message, null, null, @@ -126,7 +126,7 @@ internal sealed class ElevatedPluginInstallService } catch (Exception ex) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "elevation_failed", "Elevated plugin installation failed.", @@ -141,13 +141,13 @@ internal sealed class ElevatedPluginInstallService } } - private static ElevatedPluginInstallResult ReadResult(string resultPath) + private static ElevatedAirAppInstallResult ReadResult(string resultPath) { try { using var document = JsonDocument.Parse(File.ReadAllText(resultPath)); var root = document.RootElement; - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( GetBoolean(root, "Success"), GetString(root, "Code"), GetString(root, "Message"), @@ -158,7 +158,7 @@ internal sealed class ElevatedPluginInstallService } catch (Exception ex) { - return new ElevatedPluginInstallResult( + return new ElevatedAirAppInstallResult( false, "invalid_result", "Elevated plugin installer returned an invalid result.", diff --git a/desktop/LanMountainDesktop/Services/ExternalIpc/PublicShellControlService.cs b/desktop/LanMountainDesktop/Services/ExternalIpc/PublicShellControlService.cs index c0e21d9..9a08b66 100644 --- a/desktop/LanMountainDesktop/Services/ExternalIpc/PublicShellControlService.cs +++ b/desktop/LanMountainDesktop/Services/ExternalIpc/PublicShellControlService.cs @@ -1,6 +1,6 @@ using Avalonia; using Avalonia.Threading; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.IPC.Abstractions.Services; namespace LanMountainDesktop.Services.ExternalIpc; diff --git a/desktop/LanMountainDesktop/Services/FusedDesktopManagerService.cs b/desktop/LanMountainDesktop/Services/FusedDesktopManagerService.cs index 0e43221..a21adb3 100644 --- a/desktop/LanMountainDesktop/Services/FusedDesktopManagerService.cs +++ b/desktop/LanMountainDesktop/Services/FusedDesktopManagerService.cs @@ -8,10 +8,10 @@ using Avalonia.Platform; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.DesktopEditing; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.Abstractions; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Views; using LanMountainDesktop.Views.Components; @@ -74,7 +74,7 @@ internal sealed class FusedDesktopManagerService : IFusedDesktopManagerService { if (!OperatingSystem.IsWindows()) return; - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); if (!appSnapshot.EnableFusedDesktop) { AppLogger.Info("FusedDesktop", "Fused desktop is disabled. Skipping initialization."); @@ -101,7 +101,7 @@ internal sealed class FusedDesktopManagerService : IFusedDesktopManagerService { if (_componentRuntimeRegistry is not null) return; - var pluginRuntimeService = (Application.Current as App)?.PluginRuntimeService; + var pluginRuntimeService = (Application.Current as App)?.AirAppRuntimeService; _componentRegistry = DesktopComponentRegistryFactory.Create(pluginRuntimeService); _componentRuntimeRegistry = DesktopComponentRegistryFactory.CreateRuntimeRegistry( _componentRegistry, @@ -436,7 +436,7 @@ internal sealed class FusedDesktopManagerService : IFusedDesktopManagerService double cellSize, AppearanceThemeSnapshot snapshot) { - return descriptor.ResolveCornerRadius(new ComponentChromeContext( + return descriptor.ResolveCornerRadius(new AirAppComponentChromeContext( placement.ComponentId, placement.PlacementId, cellSize, diff --git a/desktop/LanMountainDesktop/Services/HostApplicationLifecycleService.cs b/desktop/LanMountainDesktop/Services/HostApplicationLifecycleService.cs index 837220b..e4e5d4f 100644 --- a/desktop/LanMountainDesktop/Services/HostApplicationLifecycleService.cs +++ b/desktop/LanMountainDesktop/Services/HostApplicationLifecycleService.cs @@ -2,7 +2,7 @@ using System; using System.Diagnostics; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts.Launcher; namespace LanMountainDesktop.Services; diff --git a/desktop/LanMountainDesktop/Services/IComponentInstanceSettingsStore.cs b/desktop/LanMountainDesktop/Services/IComponentInstanceSettingsStore.cs index a7ce205..5da0eff 100644 --- a/desktop/LanMountainDesktop/Services/IComponentInstanceSettingsStore.cs +++ b/desktop/LanMountainDesktop/Services/IComponentInstanceSettingsStore.cs @@ -14,9 +14,9 @@ public interface IComponentInstanceSettingsStore void DeleteForComponent(string componentId, string? placementId); - T LoadPluginSettings(string componentId, string? placementId) where T : new(); + T LoadAirAppSettings(string componentId, string? placementId) where T : new(); - void SavePluginSettings(string componentId, string? placementId, T settings); + void SaveAirAppSettings(string componentId, string? placementId, T settings); - void DeletePluginSettings(string componentId, string? placementId); + void DeleteAirAppSettings(string componentId, string? placementId); } diff --git a/desktop/LanMountainDesktop/Services/Loading/LoadingStateUsageExample.cs b/desktop/LanMountainDesktop/Services/Loading/LoadingStateUsageExample.cs index 905684e..a860f18 100644 --- a/desktop/LanMountainDesktop/Services/Loading/LoadingStateUsageExample.cs +++ b/desktop/LanMountainDesktop/Services/Loading/LoadingStateUsageExample.cs @@ -10,12 +10,12 @@ public static class LoadingStateUsageExample /// /// 示例:插件加载 /// - public static async Task LoadPluginsExample(LoadingStateManager manager) + public static async Task LoadAirAppsExample(LoadingStateManager manager) { // 注册插件加载项 var pluginItem = manager.RegisterItem( "plugins.core", - LoadingItemType.Plugin, + LoadingItemType.AirApp, "核心插件", "加载系统核心插件", new Dictionary { { "version", "1.0.0" } }); @@ -176,8 +176,8 @@ public static class LoadingStateUsageExample manager.CompleteItem("settings.load"); // 3. 加载插件 - manager.SetStage(StartupStage.LoadingPlugins, "正在加载插件..."); - await LoadPluginsExample(manager); + manager.SetStage(StartupStage.LoadingAirApps, "正在加载插件..."); + await LoadAirAppsExample(manager); // 4. 加载组件 await LoadComponentsExample(manager); diff --git a/desktop/LanMountainDesktop/Services/MaterialColorService.cs b/desktop/LanMountainDesktop/Services/MaterialColorService.cs index 46ae6ac..09f28bc 100644 --- a/desktop/LanMountainDesktop/Services/MaterialColorService.cs +++ b/desktop/LanMountainDesktop/Services/MaterialColorService.cs @@ -7,11 +7,11 @@ using Avalonia.Controls; using Avalonia.Media; using Avalonia.Styling; using Avalonia.Threading; -using LanMountainDesktop.Appearance; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts; using LanMountainDesktop.Theme; using Microsoft.Win32; @@ -194,7 +194,7 @@ internal sealed class MaterialColorService : IMaterialColorService, IDisposable { _ = sender; - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } diff --git a/desktop/LanMountainDesktop/Services/NotificationListenerService.cs b/desktop/LanMountainDesktop/Services/NotificationListenerService.cs index 5fe7c86..7d89228 100644 --- a/desktop/LanMountainDesktop/Services/NotificationListenerService.cs +++ b/desktop/LanMountainDesktop/Services/NotificationListenerService.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Avalonia.Threading; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; @@ -65,7 +65,7 @@ public sealed class NotificationListenerService : IDisposable try { - var settings = _settingsService.LoadSnapshot(SettingsScope.App); + var settings = _settingsService.LoadSnapshot(AirAppSettingsScope.App); if (!settings.NotificationBoxEnabled) { SetStatus(new NotificationBoxStatus(NotificationBoxServiceState.Unsupported, "消息盒子已在设置中关闭。", "Disabled")); @@ -133,7 +133,7 @@ public sealed class NotificationListenerService : IDisposable public void AddNotification(NotificationItem notification) { - var settings = _settingsService.LoadSnapshot(SettingsScope.App); + var settings = _settingsService.LoadSnapshot(AirAppSettingsScope.App); if (!settings.NotificationBoxEnabled) { return; diff --git a/desktop/LanMountainDesktop/Services/NotificationService.cs b/desktop/LanMountainDesktop/Services/NotificationService.cs index 1fdb324..3a487a3 100644 --- a/desktop/LanMountainDesktop/Services/NotificationService.cs +++ b/desktop/LanMountainDesktop/Services/NotificationService.cs @@ -10,7 +10,7 @@ using Avalonia.Platform; using Avalonia.Threading; using FluentAvalonia.UI.Controls; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.ViewModels; using LanMountainDesktop.Views; @@ -207,7 +207,7 @@ internal sealed class NotificationService : INotificationService try { var settingsFacade = HostSettingsFacadeProvider.GetOrCreate(); - var snapshot = settingsFacade.Settings.LoadSnapshot(PluginSdk.SettingsScope.App); + var snapshot = settingsFacade.Settings.LoadSnapshot(AirAppSdk.AirAppSettingsScope.App); return snapshot.NotificationEnabled; } catch @@ -420,7 +420,7 @@ internal sealed class NotificationWindowManager { // 濠电偛顕慨瀛橆殽閹间礁鐭楅煫鍥ㄦ磻濞岊亪鏌嶈閸撴盯骞忕€n喖绀堢憸蹇涘几閸岀偞鐓涢柛顐g箘瀛濇繝娈垮枤閸犳劗绮欐径鎰垫晣闁宠棄妫楀▓娲⒑閸涘﹦鎳勯柣妤侇殔閵嗘帡鎳滈棃娑氱獮閻熸粍妫冮崺鈧い鎺嶇劍閻ㄦ垿鏌i幙鍕瘈鐎殿噮鍋呯€靛ジ寮堕幋鐑嗕画 var settingsFacade = HostSettingsFacadeProvider.GetOrCreate(); - var snapshot = settingsFacade.Settings.LoadSnapshot(PluginSdk.SettingsScope.App); + var snapshot = settingsFacade.Settings.LoadSnapshot(AirAppSdk.AirAppSettingsScope.App); return snapshot.NotificationMaxPerPosition > 0 ? snapshot.NotificationMaxPerPosition : 5; } catch diff --git a/desktop/LanMountainDesktop/Services/PendingPluginUpgradeService.cs b/desktop/LanMountainDesktop/Services/PendingAirAppUpgradeService.cs similarity index 81% rename from desktop/LanMountainDesktop/Services/PendingPluginUpgradeService.cs rename to desktop/LanMountainDesktop/Services/PendingAirAppUpgradeService.cs index f026c6d..6fc2ce9 100644 --- a/desktop/LanMountainDesktop/Services/PendingPluginUpgradeService.cs +++ b/desktop/LanMountainDesktop/Services/PendingAirAppUpgradeService.cs @@ -1,16 +1,16 @@ using System.IO.Compression; -using LanMountainDesktop.PluginPackaging; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppPackaging; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; -public sealed class PendingPluginUpgradeService +public sealed class PendingAirAppUpgradeService { private readonly string _pluginsDirectory; private readonly PendingPluginUpgradeStore _store; private readonly PluginPackageInstaller _installer = new(); - public PendingPluginUpgradeService(string pluginsDirectory) + public PendingAirAppUpgradeService(string pluginsDirectory) { _pluginsDirectory = Path.GetFullPath(pluginsDirectory); _store = new PendingPluginUpgradeStore(_pluginsDirectory); @@ -28,7 +28,7 @@ public sealed class PendingPluginUpgradeService _store.AddPendingInstallOrUpgrade(pluginId, sourcePackagePath, targetVersion); AppLogger.Info( "PendingPluginUpgrade", - $"Added pending plugin operation. PluginId='{pluginId}'; TargetVersion='{targetVersion}'; Operation='{PendingPluginOperation.InstallOrUpgrade}'; SourcePath='{sourcePackagePath}'."); + $"Added pending plugin operation. AirAppId='{pluginId}'; TargetVersion='{targetVersion}'; Operation='{PendingPluginOperation.InstallOrUpgrade}'; SourcePath='{sourcePackagePath}'."); } public void RemovePendingUpgrade(string pluginId) @@ -38,7 +38,7 @@ public sealed class PendingPluginUpgradeService _store.RemovePendingUpgrade(pluginId); if (hadPending) { - AppLogger.Info("PendingPluginUpgrade", $"Removed pending upgrade. PluginId='{pluginId}'."); + AppLogger.Info("PendingPluginUpgrade", $"Removed pending upgrade. AirAppId='{pluginId}'."); } } @@ -51,7 +51,7 @@ public sealed class PendingPluginUpgradeService public bool HasPendingUpgrades() => _store.HasPendingUpgrades(); public PendingPluginOperationApplySummary ApplyPendingOperations( - Action? prepareManifest = null) + Action? prepareManifest = null) { var pending = _store.GetPendingUpgrades(); if (pending.Count == 0) @@ -78,7 +78,7 @@ public sealed class PendingPluginUpgradeService succeeded.Add(operation); AppLogger.Info( "PendingPluginUpgrade", - $"Applied pending plugin operation. PluginId='{operation.PluginId}'; TargetVersion='{operation.TargetVersion}'; Operation='{operation.Operation}'."); + $"Applied pending plugin operation. AirAppId='{operation.PluginId}'; TargetVersion='{operation.TargetVersion}'; Operation='{operation.Operation}'."); } catch (Exception ex) { @@ -88,7 +88,7 @@ public sealed class PendingPluginUpgradeService ex.Message)); AppLogger.Warn( "PendingPluginUpgrade", - $"Failed to apply pending plugin operation. PluginId='{operation.PluginId}'; TargetVersion='{operation.TargetVersion}'; Operation='{operation.Operation}'.", + $"Failed to apply pending plugin operation. AirAppId='{operation.PluginId}'; TargetVersion='{operation.TargetVersion}'; Operation='{operation.Operation}'.", ex); } } @@ -101,24 +101,24 @@ public sealed class PendingPluginUpgradeService return new PendingPluginOperationApplySummary(succeeded.Count, failures.Count, failures); } - private static PluginManifest ReadManifestFromPackage(string packagePath) + private static AirAppManifest ReadManifestFromPackage(string packagePath) { using var archive = ZipFile.OpenRead(packagePath); var entries = archive.Entries - .Where(entry => string.Equals(entry.Name, PluginSdkInfo.ManifestFileName, StringComparison.OrdinalIgnoreCase)) + .Where(entry => string.Equals(entry.Name, AirAppSdkInfo.ManifestFileName, StringComparison.OrdinalIgnoreCase)) .ToArray(); if (entries.Length == 0) { - throw new InvalidOperationException($"Plugin package '{packagePath}' does not contain '{PluginSdkInfo.ManifestFileName}'."); + throw new InvalidOperationException($"AirApp package '{packagePath}' does not contain '{AirAppSdkInfo.ManifestFileName}'."); } if (entries.Length > 1) { - throw new InvalidOperationException($"Plugin package '{packagePath}' contains multiple '{PluginSdkInfo.ManifestFileName}' files."); + throw new InvalidOperationException($"AirApp package '{packagePath}' contains multiple '{AirAppSdkInfo.ManifestFileName}' files."); } using var stream = entries[0].Open(); - return PluginManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); + return AirAppManifest.Load(stream, $"{packagePath}!/{entries[0].FullName}"); } } diff --git a/desktop/LanMountainDesktop/Services/PendingRestartStateService.cs b/desktop/LanMountainDesktop/Services/PendingRestartStateService.cs index 9c37fb4..a914f05 100644 --- a/desktop/LanMountainDesktop/Services/PendingRestartStateService.cs +++ b/desktop/LanMountainDesktop/Services/PendingRestartStateService.cs @@ -6,7 +6,7 @@ namespace LanMountainDesktop.Services; public static class PendingRestartStateService { public const string RenderModeReason = "RenderMode"; - public const string PluginCatalogReason = "PluginCatalog"; + public const string AirAppCatalogReason = "AirAppCatalog"; public const string SettingsWindowReason = "SettingsWindow"; public const string SystemMaterialReason = "SystemMaterial"; diff --git a/desktop/LanMountainDesktop/Services/PostHogUsageTelemetryService.cs b/desktop/LanMountainDesktop/Services/PostHogUsageTelemetryService.cs index df739ab..590887b 100644 --- a/desktop/LanMountainDesktop/Services/PostHogUsageTelemetryService.cs +++ b/desktop/LanMountainDesktop/Services/PostHogUsageTelemetryService.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using PostHog; @@ -72,7 +72,7 @@ public sealed class PostHogUsageTelemetryService : IDisposable { try { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var enabled = snapshot.UploadAnonymousUsageData; if (_isUsageEnabled == enabled && !forceSessionStart) @@ -422,7 +422,7 @@ public sealed class PostHogUsageTelemetryService : IDisposable { _ = sender; - if (e.Scope != SettingsScope.App || + if (e.Scope != AirAppSettingsScope.App || e.ChangedKeys is null || !e.ChangedKeys.Contains(nameof(AppSettingsSnapshot.UploadAnonymousUsageData), StringComparer.OrdinalIgnoreCase)) { diff --git a/desktop/LanMountainDesktop/Services/SentryCrashTelemetryService.cs b/desktop/LanMountainDesktop/Services/SentryCrashTelemetryService.cs index c38c474..df5658e 100644 --- a/desktop/LanMountainDesktop/Services/SentryCrashTelemetryService.cs +++ b/desktop/LanMountainDesktop/Services/SentryCrashTelemetryService.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; using Sentry; @@ -69,7 +69,7 @@ public sealed class SentryCrashTelemetryService : IDisposable return; } - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); shouldEnable = snapshot.UploadAnonymousCrashData; if (!force && _isEnabled == shouldEnable) @@ -343,7 +343,7 @@ public sealed class SentryCrashTelemetryService : IDisposable { _ = sender; - if (e.Scope != SettingsScope.App || + if (e.Scope != AirAppSettingsScope.App || e.ChangedKeys is null || !e.ChangedKeys.Contains(nameof(AppSettingsSnapshot.UploadAnonymousCrashData), StringComparer.OrdinalIgnoreCase)) { diff --git a/desktop/LanMountainDesktop/Services/Settings/ComponentDomainStorage.cs b/desktop/LanMountainDesktop/Services/Settings/ComponentDomainStorage.cs index 097955f..32a76f3 100644 --- a/desktop/LanMountainDesktop/Services/Settings/ComponentDomainStorage.cs +++ b/desktop/LanMountainDesktop/Services/Settings/ComponentDomainStorage.cs @@ -562,12 +562,12 @@ internal sealed class SqliteComponentDomainStorage : } } - if (document.PluginSettings is null) + if (document.AirAppSettings is null) { return; } - foreach (var pair in document.PluginSettings) + foreach (var pair in document.AirAppSettings) { if (!TrySplitInstanceKey(pair.Key, out var componentId, out var placementId)) { @@ -678,7 +678,7 @@ internal sealed class SqliteComponentDomainStorage : document = JsonSerializer.Deserialize(json, SerializerOptions) ?? new LegacyComponentDocument(); document.DefaultSettings ??= new ComponentSettingsSnapshot(); document.InstanceSettings ??= new Dictionary(StringComparer.OrdinalIgnoreCase); - document.PluginSettings ??= new Dictionary(StringComparer.OrdinalIgnoreCase); + document.AirAppSettings ??= new Dictionary(StringComparer.OrdinalIgnoreCase); return true; } @@ -837,7 +837,7 @@ internal sealed class SqliteComponentDomainStorage : public Dictionary? InstanceSettings { get; set; } = new(StringComparer.OrdinalIgnoreCase); - public Dictionary? PluginSettings { get; set; } = + public Dictionary? AirAppSettings { get; set; } = new(StringComparer.OrdinalIgnoreCase); } } diff --git a/desktop/LanMountainDesktop/Services/Settings/HostSettingsFacadeProvider.cs b/desktop/LanMountainDesktop/Services/Settings/HostSettingsFacadeProvider.cs index ed57266..b96383c 100644 --- a/desktop/LanMountainDesktop/Services/Settings/HostSettingsFacadeProvider.cs +++ b/desktop/LanMountainDesktop/Services/Settings/HostSettingsFacadeProvider.cs @@ -16,13 +16,13 @@ internal static class HostSettingsFacadeProvider } } - public static void BindPluginRuntime(PluginRuntimeService pluginRuntimeService) + public static void BindAirAppRuntime(AirAppRuntimeService pluginRuntimeService) { ArgumentNullException.ThrowIfNull(pluginRuntimeService); lock (Gate) { _instance ??= new SettingsFacadeService(pluginRuntimeService); - _instance.BindPluginRuntime(pluginRuntimeService); + _instance.BindAirAppRuntime(pluginRuntimeService); } } } diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsCatalogService.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsCatalogService.cs index 3d0e289..70ec423 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsCatalogService.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsCatalogService.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services.Settings; internal sealed class SettingsCatalogService : ISettingsCatalog { - private readonly List _sections = []; + private readonly List _sections = []; private readonly object _gate = new(); public SettingsCatalogService() @@ -15,17 +15,17 @@ internal sealed class SettingsCatalogService : ISettingsCatalog // Built-in host sections for the next settings UI. _sections.AddRange( [ - new SettingsSectionDefinition("general", SettingsCategories.General, SettingsScope.App, "settings.general.title", iconKey: "Settings", sortOrder: 0), - new SettingsSectionDefinition("material-color", SettingsCategories.Appearance, SettingsScope.App, "settings.material_color.title", iconKey: "Color", sortOrder: 8), - new SettingsSectionDefinition("appearance", SettingsCategories.Appearance, SettingsScope.App, "settings.appearance.title", iconKey: "DesignIdeas", sortOrder: 10), - new SettingsSectionDefinition("wallpaper", SettingsCategories.Appearance, SettingsScope.App, "settings.wallpaper.title", iconKey: "Image", sortOrder: 15), - new SettingsSectionDefinition("components", SettingsCategories.Components, SettingsScope.ComponentInstance, "settings.components.title", iconKey: "Apps", sortOrder: 20), - new SettingsSectionDefinition("plugins", SettingsCategories.Plugins, SettingsScope.Plugin, "settings.plugins.title", iconKey: "PuzzlePiece", sortOrder: 30), - new SettingsSectionDefinition("about", SettingsCategories.About, SettingsScope.App, "settings.about.title", iconKey: "Info", sortOrder: 40) + new AirAppSettingsSectionDefinition("general", AirAppSettingsCategories.General, AirAppSettingsScope.App, "settings.general.title", iconKey: "Settings", sortOrder: 0), + new AirAppSettingsSectionDefinition("material-color", AirAppSettingsCategories.Appearance, AirAppSettingsScope.App, "settings.material_color.title", iconKey: "Color", sortOrder: 8), + new AirAppSettingsSectionDefinition("appearance", AirAppSettingsCategories.Appearance, AirAppSettingsScope.App, "settings.appearance.title", iconKey: "DesignIdeas", sortOrder: 10), + new AirAppSettingsSectionDefinition("wallpaper", AirAppSettingsCategories.Appearance, AirAppSettingsScope.App, "settings.wallpaper.title", iconKey: "Image", sortOrder: 15), + new AirAppSettingsSectionDefinition("components", AirAppSettingsCategories.Components, AirAppSettingsScope.ComponentInstance, "settings.components.title", iconKey: "Apps", sortOrder: 20), + new AirAppSettingsSectionDefinition("plugins", AirAppSettingsCategories.AirApps, AirAppSettingsScope.AirApp, "settings.plugins.title", iconKey: "PuzzlePiece", sortOrder: 30), + new AirAppSettingsSectionDefinition("about", AirAppSettingsCategories.About, AirAppSettingsScope.App, "settings.about.title", iconKey: "Info", sortOrder: 40) ]); } - public IReadOnlyList GetSections() + public IReadOnlyList GetSections() { lock (_gate) { @@ -36,7 +36,7 @@ internal sealed class SettingsCatalogService : ISettingsCatalog } } - public IReadOnlyList GetSections(SettingsScope scope) + public IReadOnlyList GetSections(AirAppSettingsScope scope) { lock (_gate) { @@ -48,35 +48,35 @@ internal sealed class SettingsCatalogService : ISettingsCatalog } } - public void RegisterPluginSections(string pluginId, IReadOnlyList sections) + public void RegisterAirAppSections(string pluginId, IReadOnlyList sections) { ArgumentException.ThrowIfNullOrWhiteSpace(pluginId); - var normalizedPluginId = pluginId.Trim(); + var normalizedAirAppId = pluginId.Trim(); lock (_gate) { _sections.RemoveAll(section => - section.Scope == SettingsScope.Plugin && - string.Equals(section.SubjectId, normalizedPluginId, StringComparison.OrdinalIgnoreCase)); + section.Scope == AirAppSettingsScope.AirApp && + string.Equals(section.SubjectId, normalizedAirAppId, StringComparison.OrdinalIgnoreCase)); foreach (var registration in sections) { - var definition = new SettingsSectionDefinition( - id: $"{normalizedPluginId}:{registration.Id}", - category: SettingsCategories.External, - scope: SettingsScope.Plugin, + var definition = new AirAppSettingsSectionDefinition( + id: $"{normalizedAirAppId}:{registration.Id}", + category: AirAppSettingsCategories.External, + scope: AirAppSettingsScope.AirApp, titleLocalizationKey: registration.TitleLocalizationKey, descriptionLocalizationKey: registration.DescriptionLocalizationKey, iconKey: registration.IconKey, sortOrder: registration.SortOrder, - subjectId: normalizedPluginId, + subjectId: normalizedAirAppId, options: registration.Options); _sections.Add(definition); } } } - public void RemovePluginSections(string pluginId) + public void RemoveAirAppSections(string pluginId) { if (string.IsNullOrWhiteSpace(pluginId)) { @@ -86,7 +86,7 @@ internal sealed class SettingsCatalogService : ISettingsCatalog lock (_gate) { _sections.RemoveAll(section => - section.Scope == SettingsScope.Plugin && + section.Scope == AirAppSettingsScope.AirApp && string.Equals(section.SubjectId, pluginId, StringComparison.OrdinalIgnoreCase)); } } diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsContracts.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsContracts.cs index f25d892..2ed3492 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsContracts.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsContracts.cs @@ -4,11 +4,11 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Update; -using LanMountainDesktop.Services.PluginMarket; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.Services.AirAppMarket; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts.Update; namespace LanMountainDesktop.Services.Settings @@ -98,15 +98,15 @@ public sealed record UpdateSettingsState( long? PendingUpdatePublishedAtUtcMs, long? LastUpdateCheckUtcMs, string? PendingUpdateSha256); -public sealed record PluginManagementSettingsState(IReadOnlyList DisabledPluginIds); -public enum PluginPackageSourceKind +public sealed record AirAppManagementSettingsState(IReadOnlyList DisabledPluginIds); +public enum AirAppPackageSourceKind { ReleaseAsset = 0, RawFallback = 1, WorkspaceLocal = 2 } -public sealed record PluginCatalogSourceInfo( +public sealed record AirAppCatalogSourceInfo( string Id, string Name, string? Description, @@ -115,23 +115,23 @@ public sealed record PluginCatalogSourceInfo( bool IsOfficial, int Priority); -public sealed record PluginCatalogSharedContractInfo( +public sealed record AirAppCatalogSharedContractInfo( string Id, string Version, string AssemblyName); -public sealed record PluginCapabilityInfo( +public sealed record AirAppCapabilityInfo( string Id, string? Version, string? AssemblyName); -public sealed record PluginPackageSourceInfo( - PluginPackageSourceKind Kind, +public sealed record AirAppPackageSourceInfo( + AirAppPackageSourceKind Kind, string Url, string Sha256, long PackageSizeBytes); -public sealed record PluginCatalogManifestInfo( +public sealed record AirAppCatalogManifestInfo( string Id, string Name, string Description, @@ -139,13 +139,13 @@ public sealed record PluginCatalogManifestInfo( string Version, string ApiVersion, string EntranceAssembly, - IReadOnlyList SharedContracts); + IReadOnlyList SharedContracts); -public sealed record PluginCatalogCompatibilityInfo( +public sealed record AirAppCatalogCompatibilityInfo( string MinHostVersion, string ApiVersion); -public sealed record PluginCatalogRepositoryInfo( +public sealed record AirAppCatalogRepositoryInfo( string IconUrl, string ProjectUrl, string ReadmeUrl, @@ -154,7 +154,7 @@ public sealed record PluginCatalogRepositoryInfo( IReadOnlyList Tags, string ReleaseNotes); -public sealed record PluginCatalogPublicationInfo( +public sealed record AirAppCatalogPublicationInfo( string ReleaseTag, string ReleaseAssetName, DateTimeOffset PublishedAt, @@ -163,13 +163,13 @@ public sealed record PluginCatalogPublicationInfo( string Sha256, string? Md5); -public sealed record PluginCatalogItemInfo( - PluginCatalogManifestInfo Manifest, - PluginCatalogCompatibilityInfo Compatibility, - PluginCatalogRepositoryInfo Repository, - PluginCatalogPublicationInfo Publication, - IReadOnlyList PackageSources, - IReadOnlyList Capabilities) +public sealed record AirAppCatalogItemInfo( + AirAppCatalogManifestInfo Manifest, + AirAppCatalogCompatibilityInfo Compatibility, + AirAppCatalogRepositoryInfo Repository, + AirAppCatalogPublicationInfo Publication, + IReadOnlyList PackageSources, + IReadOnlyList Capabilities) { public string Id => Manifest.Id; @@ -203,7 +203,7 @@ public sealed record PluginCatalogItemInfo( public IReadOnlyList Tags => Repository.Tags; - public IReadOnlyList SharedContracts => Manifest.SharedContracts; + public IReadOnlyList SharedContracts => Manifest.SharedContracts; public DateTimeOffset PublishedAt => Publication.PublishedAt; @@ -216,51 +216,51 @@ public sealed record PluginCatalogItemInfo( public string ReleaseNotes => Repository.ReleaseNotes; } -public sealed record PluginCatalogIndexResult( +public sealed record AirAppCatalogIndexResult( bool Success, - IReadOnlyList Plugins, - IReadOnlyList Sources, + IReadOnlyList AirApps, + IReadOnlyList Sources, string? Source, string? SourceLocation, string? WarningMessage, string? ErrorMessage); -public sealed record PluginInstallDiagnostic( +public sealed record AirAppInstallDiagnostic( string Code, string Message, string? Details = null); -public sealed record PluginCatalogInstallResult( +public sealed record AirAppCatalogInstallResult( bool Success, - string? PluginId, - string? PluginName, - PluginManifest? InstalledManifest, - IReadOnlyList Diagnostics, + string? AirAppId, + string? AirAppName, + AirAppManifest? InstalledManifest, + IReadOnlyList Diagnostics, string? ErrorMessage); -public interface IPluginCatalogSourceProvider +public interface IAirAppCatalogSourceProvider { - Task LoadCatalogAsync(CancellationToken cancellationToken = default); + Task LoadCatalogAsync(CancellationToken cancellationToken = default); } -public interface IPluginCatalogService : IPluginCatalogSourceProvider +public interface IAirAppCatalogService : IAirAppCatalogSourceProvider { - Task InstallAsync(string pluginId, CancellationToken cancellationToken = default); + Task InstallAsync(string pluginId, CancellationToken cancellationToken = default); } public interface IPackageSourceResolver { - IReadOnlyList ResolveSources(PluginCatalogItemInfo item); + IReadOnlyList ResolveSources(AirAppCatalogItemInfo item); } -public interface IPluginCompatibilityEvaluator +public interface IAirAppCompatibilityEvaluator { - PluginInstallDiagnostic? Evaluate(PluginCatalogItemInfo item, Version? hostVersion); + AirAppInstallDiagnostic? Evaluate(AirAppCatalogItemInfo item, Version? hostVersion); } -public interface IPluginInstallOrchestrator +public interface IAirAppInstallOrchestrator { - Task InstallAsync(PluginCatalogItemInfo item, CancellationToken cancellationToken = default); + Task InstallAsync(AirAppCatalogItemInfo item, CancellationToken cancellationToken = default); } public interface IGridSettingsService @@ -402,19 +402,19 @@ public interface ILauncherPolicyService void Save(LauncherSettingsSnapshot snapshot); } -public interface IPluginManagementSettingsService +public interface IAirAppManagementSettingsService { - PluginManagementSettingsState Get(); - void Save(PluginManagementSettingsState state); - IReadOnlyList GetInstalledPlugins(); - bool SetPluginEnabled(string pluginId, bool isEnabled); - bool DeleteInstalledPlugin(string pluginId); + AirAppManagementSettingsState Get(); + void Save(AirAppManagementSettingsState state); + IReadOnlyList GetInstalledAirApps(); + bool SetAirAppEnabled(string pluginId, bool isEnabled); + bool DeleteInstalledAirApp(string pluginId); } -public interface IPluginCatalogSettingsService : IPluginCatalogSourceProvider +public interface IAirAppCatalogSettingsService : IAirAppCatalogSourceProvider { - new Task LoadCatalogAsync(CancellationToken cancellationToken = default); - Task InstallAsync(string pluginId, CancellationToken cancellationToken = default); + new Task LoadCatalogAsync(CancellationToken cancellationToken = default); + Task InstallAsync(string pluginId, CancellationToken cancellationToken = default); } public interface IApplicationInfoService @@ -440,16 +440,16 @@ public interface ISettingsFacadeService IUpdateSettingsService Update { get; } ILauncherCatalogService LauncherCatalog { get; } ILauncherPolicyService LauncherPolicy { get; } - IPluginManagementSettingsService PluginManagement { get; } - IPluginCatalogSettingsService PluginCatalog { get; } + IAirAppManagementSettingsService AirAppManagement { get; } + IAirAppCatalogSettingsService AirAppCatalog { get; } IApplicationInfoService ApplicationInfo { get; } } } -namespace LanMountainDesktop.Services.PluginMarket +namespace LanMountainDesktop.Services.AirAppMarket { - internal enum PluginPackageSourceKind + internal enum AirAppPackageSourceKind { ReleaseAsset = 0, RawFallback = 1, diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsDomainServices.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsDomainServices.cs index 320a8e8..58fe820 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsDomainServices.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsDomainServices.cs @@ -8,12 +8,12 @@ using System.Threading.Tasks; using Avalonia.Media; using Avalonia.Media.Imaging; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Plonds; using LanMountainDesktop.Services.Update; -using LanMountainDesktop.Settings.Core; -using LanMountainDesktop.Services.PluginMarket; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.Services.AirAppMarket; using LanMountainDesktop.Shared.Contracts.Update; namespace LanMountainDesktop.Services.Settings; @@ -44,7 +44,7 @@ internal sealed class GridSettingsService : IGridSettingsService snapshot.GridSpacingPreset = state.SpacingPreset; snapshot.DesktopEdgeInsetPercent = state.EdgeInsetPercent; _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -134,7 +134,7 @@ internal sealed class WallpaperSettingsService : IWallpaperSettingsService : state.Placement.Trim(); snapshot.SystemWallpaperRefreshIntervalSeconds = NormalizeRefreshInterval(state.SystemWallpaperRefreshIntervalSeconds); _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -371,7 +371,7 @@ internal sealed class ThemeAppearanceService : IThemeAppearanceService } _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: changedKeys); } @@ -481,7 +481,7 @@ internal sealed class StatusBarSettingsService : IStatusBarSettingsService snapshot.StatusBarShadowColor = state.ShadowColor; snapshot.StatusBarShadowOpacity = state.ShadowOpacity; _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -540,7 +540,7 @@ internal sealed class TextCapsuleSettingsService : ITextCapsuleSettingsService snapshot.TextCapsulePosition = state.Position; snapshot.TextCapsuleTransparentBackground = state.TransparentBackground; _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -629,7 +629,7 @@ internal sealed class WeatherSettingsService : IWeatherSettingsService, IDisposa snapshot.WeatherNoTlsRequests = state.NoTlsRequests; snapshot.WeatherLocationQuery = state.LocationQuery; _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -706,7 +706,7 @@ internal sealed class RegionSettingsService : IRegionSettingsService ? null : state.TimeZoneId.Trim(); _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -779,7 +779,7 @@ internal sealed class PrivacySettingsService : IPrivacySettingsService "PrivacySettings", $"Saving: UploadAnonymousCrashData={state.UploadAnonymousCrashData}, UploadAnonymousUsageData={state.UploadAnonymousUsageData}"); _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: changedKeys); } @@ -891,7 +891,7 @@ internal sealed class UpdateSettingsService : IUpdateSettingsService, IDisposabl ? null : state.PendingUpdateSha256.Trim().ToLowerInvariant(); _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -1638,66 +1638,66 @@ internal sealed class LauncherPolicyService : ILauncherPolicyService } } -internal sealed class PluginManagementSettingsService : IPluginManagementSettingsService +internal sealed class AirAppManagementSettingsService : IAirAppManagementSettingsService { private readonly ISettingsService _settingsService; - private PluginRuntimeService? _pluginRuntimeService; + private AirAppRuntimeService? _pluginRuntimeService; - public PluginManagementSettingsService(ISettingsService settingsService, PluginRuntimeService? pluginRuntimeService) + public AirAppManagementSettingsService(ISettingsService settingsService, AirAppRuntimeService? pluginRuntimeService) { _settingsService = settingsService ?? throw new ArgumentNullException(nameof(settingsService)); _pluginRuntimeService = pluginRuntimeService; } - public void SetPluginRuntime(PluginRuntimeService? pluginRuntimeService) + public void SetAirAppRuntime(AirAppRuntimeService? pluginRuntimeService) { _pluginRuntimeService = pluginRuntimeService; } - public PluginManagementSettingsState Get() + public AirAppManagementSettingsState Get() { var snapshot = _settingsService.Load(); - return new PluginManagementSettingsState(snapshot.DisabledPluginIds?.ToArray() ?? []); + return new AirAppManagementSettingsState(snapshot.DisabledPluginIds?.ToArray() ?? []); } - public void Save(PluginManagementSettingsState state) + public void Save(AirAppManagementSettingsState state) { var snapshot = _settingsService.Load(); snapshot.DisabledPluginIds = state.DisabledPluginIds?.ToList() ?? []; _settingsService.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [nameof(AppSettingsSnapshot.DisabledPluginIds)]); } - public IReadOnlyList GetInstalledPlugins() + public IReadOnlyList GetInstalledAirApps() { - return _pluginRuntimeService?.GetInstalledPluginsSnapshot() ?? []; + return _pluginRuntimeService?.GetInstalledAirAppsSnapshot() ?? []; } - public bool SetPluginEnabled(string pluginId, bool isEnabled) + public bool SetAirAppEnabled(string pluginId, bool isEnabled) { - return _pluginRuntimeService?.SetPluginEnabled(pluginId, isEnabled) ?? false; + return _pluginRuntimeService?.SetAirAppEnabled(pluginId, isEnabled) ?? false; } - public bool DeleteInstalledPlugin(string pluginId) + public bool DeleteInstalledAirApp(string pluginId) { - return _pluginRuntimeService?.DeleteInstalledPlugin(pluginId) ?? false; + return _pluginRuntimeService?.DeleteInstalledAirApp(pluginId) ?? false; } } -internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsService, IDisposable +internal sealed class AirAppCatalogSettingsService : IAirAppCatalogSettingsService, IDisposable { - private PluginRuntimeService? _pluginRuntimeService; + private AirAppRuntimeService? _pluginRuntimeService; private AirAppMarketIndexService _indexService; private AirAppMarketInstallService? _installService; - private readonly Dictionary _cachedPlugins = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _cachedAirApps = new(StringComparer.OrdinalIgnoreCase); - public PluginCatalogSettingsService(PluginRuntimeService? pluginRuntimeService) + public AirAppCatalogSettingsService(AirAppRuntimeService? pluginRuntimeService) { _pluginRuntimeService = pluginRuntimeService; - var dataRoot = AppDataPathProvider.GetPluginMarketDirectory(); + var dataRoot = AppDataPathProvider.GetAirAppMarketDirectory(); var cacheService = new AirAppMarketCacheService(dataRoot); _indexService = new AirAppMarketIndexService(cacheService); if (_pluginRuntimeService is not null) @@ -1706,7 +1706,7 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi } } - public void SetPluginRuntime(PluginRuntimeService? pluginRuntimeService) + public void SetAirAppRuntime(AirAppRuntimeService? pluginRuntimeService) { _pluginRuntimeService = pluginRuntimeService; _installService?.Dispose(); @@ -1717,30 +1717,30 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi return; } - var dataRoot = AppDataPathProvider.GetPluginMarketDirectory(); + var dataRoot = AppDataPathProvider.GetAirAppMarketDirectory(); _installService = new AirAppMarketInstallService(_pluginRuntimeService, dataRoot); } - public Task LoadCatalogAsync(CancellationToken cancellationToken = default) + public Task LoadCatalogAsync(CancellationToken cancellationToken = default) { return LoadCatalogCoreAsync(cancellationToken); } - public Task InstallAsync( + public Task InstallAsync( string pluginId, CancellationToken cancellationToken = default) { return InstallCatalogCoreAsync(pluginId, cancellationToken); } - private async Task LoadCatalogCoreAsync(CancellationToken cancellationToken = default) + private async Task LoadCatalogCoreAsync(CancellationToken cancellationToken = default) { var result = await _indexService.LoadAsync(cancellationToken).ConfigureAwait(false); var sources = BuildCatalogSources(result.Source?.ToString(), result.SourceLocation, result.WarningMessage); if (!result.Success || result.Document is null) { - _cachedPlugins.Clear(); - return new PluginCatalogIndexResult( + _cachedAirApps.Clear(); + return new AirAppCatalogIndexResult( false, [], sources, @@ -1750,16 +1750,16 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi result.ErrorMessage); } - _cachedPlugins.Clear(); - var plugins = result.Document.Plugins + _cachedAirApps.Clear(); + var plugins = result.Document.AirApps .Select(entry => { - _cachedPlugins[entry.Id] = entry; + _cachedAirApps[entry.Id] = entry; return MapCatalogItem(entry); }) .ToArray(); - return new PluginCatalogIndexResult( + return new AirAppCatalogIndexResult( true, plugins, sources, @@ -1769,71 +1769,71 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi null); } - private async Task InstallCatalogCoreAsync( + private async Task InstallCatalogCoreAsync( string pluginId, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(pluginId)) { - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( false, null, null, null, - [new PluginInstallDiagnostic("invalid_request", "Plugin id is required.")], - "Plugin id is required."); + [new AirAppInstallDiagnostic("invalid_request", "AirApp id is required.")], + "AirApp id is required."); } if (_installService is null || _pluginRuntimeService is null) { - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( false, pluginId, null, null, - [new PluginInstallDiagnostic("runtime_unavailable", "Plugin runtime is unavailable.")], - "Plugin runtime is unavailable."); + [new AirAppInstallDiagnostic("runtime_unavailable", "AirApp runtime is unavailable.")], + "AirApp runtime is unavailable."); } - if (!_cachedPlugins.TryGetValue(pluginId, out var entry)) + if (!_cachedAirApps.TryGetValue(pluginId, out var entry)) { var load = await LoadCatalogCoreAsync(cancellationToken).ConfigureAwait(false); if (!load.Success) { - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( false, pluginId, null, null, - [new PluginInstallDiagnostic("catalog_load_failed", load.ErrorMessage ?? "Failed to load the plugin catalog.")], + [new AirAppInstallDiagnostic("catalog_load_failed", load.ErrorMessage ?? "Failed to load the plugin catalog.")], load.ErrorMessage); } - if (!_cachedPlugins.TryGetValue(pluginId, out entry)) + if (!_cachedAirApps.TryGetValue(pluginId, out entry)) { - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( false, pluginId, null, null, - [new PluginInstallDiagnostic("not_found", "Plugin was not found in the official catalog.")], - "Plugin was not found in the official catalog."); + [new AirAppInstallDiagnostic("not_found", "AirApp was not found in the official catalog.")], + "AirApp was not found in the official catalog."); } } var result = await _installService.InstallAsync(entry, cancellationToken).ConfigureAwait(false); if (!result.Success) { - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( false, entry.Id, entry.Name, null, - [new PluginInstallDiagnostic("install_failed", result.ErrorMessage ?? "Plugin install failed.")], + [new AirAppInstallDiagnostic("install_failed", result.ErrorMessage ?? "AirApp install failed.")], result.ErrorMessage); } - return new PluginCatalogInstallResult( + return new AirAppCatalogInstallResult( true, result.Manifest?.Id ?? entry.Id, result.Manifest?.Name ?? entry.Name, @@ -1842,9 +1842,9 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi null); } - private static PluginCatalogItemInfo MapCatalogItem(AirAppMarketPluginEntry entry) + private static AirAppCatalogItemInfo MapCatalogItem(AirAppMarketAirAppEntry entry) { - var manifest = new PluginCatalogManifestInfo( + var manifest = new AirAppCatalogManifestInfo( entry.Id, entry.Name, entry.Description, @@ -1853,17 +1853,17 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi entry.ApiVersion, entry.EntranceAssembly, entry.SharedContracts - .Select(contract => new PluginCatalogSharedContractInfo( + .Select(contract => new AirAppCatalogSharedContractInfo( contract.Id, contract.Version, contract.AssemblyName)) .ToArray()); - var compatibility = new PluginCatalogCompatibilityInfo( + var compatibility = new AirAppCatalogCompatibilityInfo( entry.MinHostVersion, entry.ApiVersion); - var repository = new PluginCatalogRepositoryInfo( + var repository = new AirAppCatalogRepositoryInfo( entry.IconUrl, entry.ProjectUrl, entry.ReadmeUrl, @@ -1872,7 +1872,7 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi entry.Tags.ToArray(), entry.ReleaseNotes); - var publication = new PluginCatalogPublicationInfo( + var publication = new AirAppCatalogPublicationInfo( entry.ReleaseTag, entry.ReleaseAssetName, entry.PublishedAt, @@ -1883,7 +1883,7 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi var sources = BuildPackageSources(entry); - return new PluginCatalogItemInfo( + return new AirAppCatalogItemInfo( manifest, compatibility, repository, @@ -1892,26 +1892,26 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi BuildCapabilities(entry)); } - private static IReadOnlyList BuildCapabilities(AirAppMarketPluginEntry entry) + private static IReadOnlyList BuildCapabilities(AirAppMarketAirAppEntry entry) { - var capabilities = new List(); + var capabilities = new List(); capabilities.AddRange(entry.SharedContracts.Select(contract => - new PluginCapabilityInfo(contract.Id, contract.Version, contract.AssemblyName))); + new AirAppCapabilityInfo(contract.Id, contract.Version, contract.AssemblyName))); capabilities.AddRange(entry.DesktopComponents.Select(id => - new PluginCapabilityInfo(id, null, null))); + new AirAppCapabilityInfo(id, null, null))); capabilities.AddRange(entry.SettingsSections.Select(id => - new PluginCapabilityInfo(id, null, null))); + new AirAppCapabilityInfo(id, null, null))); capabilities.AddRange(entry.Exports.Select(id => - new PluginCapabilityInfo(id, null, null))); + new AirAppCapabilityInfo(id, null, null))); capabilities.AddRange(entry.MessageTypes.Select(id => - new PluginCapabilityInfo(id, null, null))); + new AirAppCapabilityInfo(id, null, null))); return capabilities .DistinctBy(capability => $"{capability.Id}@{capability.Version}@{capability.AssemblyName}") .ToArray(); } - private static IReadOnlyList BuildPackageSources(AirAppMarketPluginEntry entry) + private static IReadOnlyList BuildPackageSources(AirAppMarketAirAppEntry entry) { var sources = entry.GetPackageSourcesInInstallOrder(); if (sources.Count == 0) @@ -1920,13 +1920,13 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi } return sources - .Select(source => new PluginPackageSourceInfo( + .Select(source => new AirAppPackageSourceInfo( source.SourceKind switch { - LanMountainDesktop.Services.PluginMarket.PluginPackageSourceKind.ReleaseAsset => PluginPackageSourceKind.ReleaseAsset, - LanMountainDesktop.Services.PluginMarket.PluginPackageSourceKind.RawFallback => PluginPackageSourceKind.RawFallback, - LanMountainDesktop.Services.PluginMarket.PluginPackageSourceKind.WorkspaceLocal => PluginPackageSourceKind.WorkspaceLocal, - _ => PluginPackageSourceKind.RawFallback + LanMountainDesktop.Services.AirAppMarket.AirAppPackageSourceKind.ReleaseAsset => AirAppPackageSourceKind.ReleaseAsset, + LanMountainDesktop.Services.AirAppMarket.AirAppPackageSourceKind.RawFallback => AirAppPackageSourceKind.RawFallback, + LanMountainDesktop.Services.AirAppMarket.AirAppPackageSourceKind.WorkspaceLocal => AirAppPackageSourceKind.WorkspaceLocal, + _ => AirAppPackageSourceKind.RawFallback }, source.Url, entry.Sha256, @@ -1934,7 +1934,7 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi .ToArray(); } - private static IReadOnlyList BuildCatalogSources( + private static IReadOnlyList BuildCatalogSources( string? sourceId, string? sourceLocation, string? warningMessage) @@ -1950,7 +1950,7 @@ internal sealed class PluginCatalogSettingsService : IPluginCatalogSettingsServi return [ - new PluginCatalogSourceInfo( + new AirAppCatalogSourceInfo( normalizedSourceId, normalizedSourceId, string.IsNullOrWhiteSpace(warningMessage) ? null : warningMessage.Trim(), @@ -2049,11 +2049,11 @@ internal sealed class ApplicationInfoService : IApplicationInfoService internal sealed class SettingsFacadeService : ISettingsFacadeService, IDisposable { private readonly UpdateSettingsService _updateSettingsService; - private readonly PluginCatalogSettingsService _pluginCatalogSettingsService; - private readonly PluginManagementSettingsService _pluginManagementSettingsService; + private readonly AirAppCatalogSettingsService _pluginCatalogSettingsService; + private readonly AirAppManagementSettingsService _pluginManagementSettingsService; private readonly WeatherSettingsService _weatherSettingsService; - public SettingsFacadeService(PluginRuntimeService? pluginRuntimeService = null) + public SettingsFacadeService(AirAppRuntimeService? pluginRuntimeService = null) { Settings = new SettingsService(); Catalog = new SettingsCatalogService(); @@ -2071,10 +2071,10 @@ internal sealed class SettingsFacadeService : ISettingsFacadeService, IDisposabl Update = _updateSettingsService; LauncherCatalog = new LauncherCatalogService(); LauncherPolicy = new LauncherPolicyService(); - _pluginManagementSettingsService = new PluginManagementSettingsService(Settings, pluginRuntimeService); - PluginManagement = _pluginManagementSettingsService; - _pluginCatalogSettingsService = new PluginCatalogSettingsService(pluginRuntimeService); - PluginCatalog = _pluginCatalogSettingsService; + _pluginManagementSettingsService = new AirAppManagementSettingsService(Settings, pluginRuntimeService); + AirAppManagement = _pluginManagementSettingsService; + _pluginCatalogSettingsService = new AirAppCatalogSettingsService(pluginRuntimeService); + AirAppCatalog = _pluginCatalogSettingsService; ApplicationInfo = new ApplicationInfoService(); } @@ -2106,16 +2106,16 @@ internal sealed class SettingsFacadeService : ISettingsFacadeService, IDisposabl public ILauncherPolicyService LauncherPolicy { get; } - public IPluginManagementSettingsService PluginManagement { get; } + public IAirAppManagementSettingsService AirAppManagement { get; } - public IPluginCatalogSettingsService PluginCatalog { get; } + public IAirAppCatalogSettingsService AirAppCatalog { get; } public IApplicationInfoService ApplicationInfo { get; } - public void BindPluginRuntime(PluginRuntimeService? pluginRuntimeService) + public void BindAirAppRuntime(AirAppRuntimeService? pluginRuntimeService) { - _pluginManagementSettingsService.SetPluginRuntime(pluginRuntimeService); - _pluginCatalogSettingsService.SetPluginRuntime(pluginRuntimeService); + _pluginManagementSettingsService.SetAirAppRuntime(pluginRuntimeService); + _pluginCatalogSettingsService.SetAirAppRuntime(pluginRuntimeService); } public void Dispose() diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsPageRegistry.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsPageRegistry.cs index 30d01e6..98a33e2 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsPageRegistry.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsPageRegistry.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Reflection; using Avalonia.Controls; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; -using LanMountainDesktop.Plugins; -using LanMountainDesktop.Services.PluginMarket; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirApps; +using LanMountainDesktop.Services.AirAppMarket; using LanMountainDesktop.Services; using LanMountainDesktop.ViewModels; using LanMountainDesktop.Views.SettingsPages; @@ -24,7 +24,7 @@ public sealed class SettingsPageDescriptor string? description, string iconKey, string? selectedIconKey, - SettingsPageCategory category, + AirAppSettingsPageCategory category, int sortOrder, string? pluginId, bool isBuiltIn, @@ -46,7 +46,7 @@ public sealed class SettingsPageDescriptor SelectedIconKey = string.IsNullOrWhiteSpace(selectedIconKey) ? IconKey : selectedIconKey.Trim(); Category = category; SortOrder = sortOrder; - PluginId = string.IsNullOrWhiteSpace(pluginId) ? null : pluginId.Trim(); + AirAppId = string.IsNullOrWhiteSpace(pluginId) ? null : pluginId.Trim(); IsBuiltIn = isBuiltIn; HideDefault = hideDefault; HidePageTitle = hidePageTitle; @@ -65,11 +65,11 @@ public sealed class SettingsPageDescriptor public string SelectedIconKey { get; } - public SettingsPageCategory Category { get; } + public AirAppSettingsPageCategory Category { get; } public int SortOrder { get; } - public string? PluginId { get; } + public string? AirAppId { get; } public bool IsBuiltIn { get; } @@ -98,7 +98,7 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable private readonly ISettingsFacadeService _settingsFacade; private readonly IHostApplicationLifecycle _hostApplicationLifecycle; private readonly LocalizationService _localizationService; - private readonly Func _pluginRuntimeAccessor; + private readonly Func _pluginRuntimeAccessor; private readonly object _gate = new(); private readonly List _pages = []; private ServiceProvider? _hostServices; @@ -107,7 +107,7 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable ISettingsFacadeService settingsFacade, IHostApplicationLifecycle hostApplicationLifecycle, LocalizationService localizationService, - Func pluginRuntimeAccessor) + Func pluginRuntimeAccessor) { _settingsFacade = settingsFacade ?? throw new ArgumentNullException(nameof(settingsFacade)); _hostApplicationLifecycle = hostApplicationLifecycle ?? throw new ArgumentNullException(nameof(hostApplicationLifecycle)); @@ -135,10 +135,10 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable return; } - foreach (var loadedPlugin in pluginRuntime.LoadedPlugins) + foreach (var loadedAirApp in pluginRuntime.LoadedAirApps) { - RegisterPluginPages(loadedPlugin); - RegisterLegacyPluginSections(loadedPlugin); + RegisterAirAppPages(loadedAirApp); + RegisterLegacyAirAppSections(loadedAirApp); } SortPages(); @@ -205,21 +205,21 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable bool isBuiltIn) { var isDevModeEnabled = _settingsFacade.Settings - .LoadSnapshot(SettingsScope.App) + .LoadSnapshot(AirAppSettingsScope.App) .IsDevModeEnabled; foreach (var pageType in assembly.GetTypes() - .Where(type => !type.IsAbstract && typeof(SettingsPageBase).IsAssignableFrom(type))) + .Where(type => !type.IsAbstract && typeof(AirAppSettingsPageBase).IsAssignableFrom(type))) { - var pageInfo = pageType.GetCustomAttribute(); + var pageInfo = pageType.GetCustomAttribute(); if (pageInfo is null) { continue; } - var category = isBuiltIn ? pageInfo.Category : SettingsPageCategory.Plugins; + var category = isBuiltIn ? pageInfo.Category : AirAppSettingsPageCategory.AirApps; - if (category == SettingsPageCategory.Dev && !isDevModeEnabled) + if (category == AirAppSettingsPageCategory.Dev && !isDevModeEnabled) { continue; } @@ -245,22 +245,22 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable } } - private void RegisterPluginPages(LoadedPlugin loadedPlugin) + private void RegisterAirAppPages(LoadedAirApp loadedAirApp) { RegisterAssemblyPages( - loadedPlugin.Assembly, - loadedPlugin.Services, - loadedPlugin.Manifest.Id, + loadedAirApp.Assembly, + loadedAirApp.Services, + loadedAirApp.Manifest.Id, isBuiltIn: false); } - private void RegisterLegacyPluginSections(LoadedPlugin loadedPlugin) + private void RegisterLegacyAirAppSections(LoadedAirApp loadedAirApp) { - var localizer = PluginLocalizer.Create(loadedPlugin.RuntimeContext); + var localizer = AirAppLocalizer.Create(loadedAirApp.RuntimeContext); - foreach (var section in loadedPlugin.SettingsSections) + foreach (var section in loadedAirApp.SettingsSections) { - var pageId = $"plugin:{loadedPlugin.Manifest.Id}:{section.Id}"; + var pageId = $"plugin:{loadedAirApp.Manifest.Id}:{section.Id}"; var title = localizer.GetString(section.TitleLocalizationKey, section.TitleLocalizationKey); var description = string.IsNullOrWhiteSpace(section.DescriptionLocalizationKey) ? null @@ -271,17 +271,17 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable if (section.CustomViewType is not null) { var customViewType = section.CustomViewType; - var pluginServices = loadedPlugin.Services; + var pluginServices = loadedAirApp.Services; factory = hostContext => CreatePage(pluginServices, customViewType, hostContext); } else { factory = hostContext => { - var page = new GeneratedPluginSettingsPage( - new PluginGeneratedSettingsPageViewModel( + var page = new GeneratedAirAppSettingsPage( + new AirAppGeneratedSettingsPageViewModel( _settingsFacade.Settings, - loadedPlugin.Manifest.Id, + loadedAirApp.Manifest.Id, section, localizer)); page.InitializeHostContext(hostContext); @@ -295,9 +295,9 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable description, section.IconKey, section.IconKey, - SettingsPageCategory.Plugins, + AirAppSettingsPageCategory.AirApps, 200 + section.SortOrder, - loadedPlugin.Manifest.Id, + loadedAirApp.Manifest.Id, isBuiltIn: false, hideDefault: false, hidePageTitle: false, @@ -323,7 +323,7 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable return sortOrderCompare; } - var pluginCompare = string.Compare(left.PluginId, right.PluginId, StringComparison.OrdinalIgnoreCase); + var pluginCompare = string.Compare(left.AirAppId, right.AirAppId, StringComparison.OrdinalIgnoreCase); if (pluginCompare != 0) { return pluginCompare; @@ -354,7 +354,7 @@ internal sealed class SettingsPageRegistry : ISettingsPageRegistry, IDisposable ISettingsPageHostContext hostContext) { var page = (Control)ActivatorUtilities.CreateInstance(services, pageType); - if (page is SettingsPageBase settingsPage) + if (page is AirAppSettingsPageBase settingsPage) { settingsPage.InitializeHostContext(hostContext); } diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsService.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsService.cs index a2c0387..2f316f5 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsService.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsService.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text.Json; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services.Settings; @@ -32,20 +32,20 @@ internal sealed class SettingsService : ISettingsService public event EventHandler? Changed; - public T LoadSnapshot(SettingsScope scope, string? subjectId = null, string? placementId = null) where T : new() + public T LoadSnapshot(AirAppSettingsScope scope, string? subjectId = null, string? placementId = null) where T : new() { return scope switch { - SettingsScope.App => ConvertSnapshot(_appSettingsService.Load()), - SettingsScope.Launcher => ConvertSnapshot(_launcherSettingsService.Load()), - SettingsScope.ComponentInstance => LoadComponentSnapshot(subjectId, placementId), - SettingsScope.Plugin => LoadSection(scope, EnsureKey(subjectId), sectionId: "__snapshot__", placementId), + AirAppSettingsScope.App => ConvertSnapshot(_appSettingsService.Load()), + AirAppSettingsScope.Launcher => ConvertSnapshot(_launcherSettingsService.Load()), + AirAppSettingsScope.ComponentInstance => LoadComponentSnapshot(subjectId, placementId), + AirAppSettingsScope.AirApp => LoadSection(scope, EnsureKey(subjectId), sectionId: "__snapshot__", placementId), _ => new T() }; } public void SaveSnapshot( - SettingsScope scope, + AirAppSettingsScope scope, T snapshot, string? subjectId = null, string? placementId = null, @@ -54,16 +54,16 @@ internal sealed class SettingsService : ISettingsService { switch (scope) { - case SettingsScope.App: + case AirAppSettingsScope.App: _appSettingsService.Save(ConvertSnapshot(snapshot)); break; - case SettingsScope.Launcher: + case AirAppSettingsScope.Launcher: _launcherSettingsService.Save(ConvertSnapshot(snapshot)); break; - case SettingsScope.ComponentInstance: + case AirAppSettingsScope.ComponentInstance: SaveComponentSnapshot(subjectId, placementId, snapshot); break; - case SettingsScope.Plugin: + case AirAppSettingsScope.AirApp: SaveSection(scope, EnsureKey(subjectId), "__snapshot__", snapshot, placementId, changedKeys); break; } @@ -72,24 +72,24 @@ internal sealed class SettingsService : ISettingsService } public T LoadSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null) where T : new() { - if (scope == SettingsScope.ComponentInstance) + if (scope == AirAppSettingsScope.ComponentInstance) { return _componentMessageStore.LoadSection(EnsureKey(subjectId), placementId, EnsureKey(sectionId)); } - if (scope != SettingsScope.Plugin) + if (scope != AirAppSettingsScope.AirApp) { return new T(); } lock (_pluginSettingsGate) { - var document = LoadPluginDocumentLocked(); + var document = LoadAirAppDocumentLocked(); if (!document.Sections.TryGetValue(EnsureKey(subjectId), out var pluginSections) || !pluginSections.TryGetValue(EnsureKey(sectionId), out var payload)) { @@ -101,28 +101,28 @@ internal sealed class SettingsService : ISettingsService } public void SaveSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, T section, string? placementId = null, IReadOnlyCollection? changedKeys = null) { - if (scope == SettingsScope.ComponentInstance) + if (scope == AirAppSettingsScope.ComponentInstance) { _componentMessageStore.SaveSection(EnsureKey(subjectId), placementId, EnsureKey(sectionId), section); OnChanged(new SettingsChangedEvent(scope, subjectId, placementId, sectionId, changedKeys)); return; } - if (scope != SettingsScope.Plugin) + if (scope != AirAppSettingsScope.AirApp) { return; } lock (_pluginSettingsGate) { - var document = LoadPluginDocumentLocked(); + var document = LoadAirAppDocumentLocked(); var pluginId = EnsureKey(subjectId); if (!document.Sections.TryGetValue(pluginId, out var pluginSections)) { @@ -131,29 +131,29 @@ internal sealed class SettingsService : ISettingsService } pluginSections[EnsureKey(sectionId)] = JsonSerializer.SerializeToElement(section, SerializerOptions).Clone(); - PersistPluginDocumentLocked(document); + PersistAirAppDocumentLocked(document); } OnChanged(new SettingsChangedEvent(scope, subjectId, placementId, sectionId, changedKeys)); } - public void DeleteSection(SettingsScope scope, string subjectId, string sectionId, string? placementId = null) + public void DeleteSection(AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null) { - if (scope == SettingsScope.ComponentInstance) + if (scope == AirAppSettingsScope.ComponentInstance) { _componentMessageStore.DeleteSection(EnsureKey(subjectId), placementId, EnsureKey(sectionId)); OnChanged(new SettingsChangedEvent(scope, subjectId, placementId, sectionId)); return; } - if (scope != SettingsScope.Plugin) + if (scope != AirAppSettingsScope.AirApp) { return; } lock (_pluginSettingsGate) { - var document = LoadPluginDocumentLocked(); + var document = LoadAirAppDocumentLocked(); var pluginId = EnsureKey(subjectId); if (document.Sections.TryGetValue(pluginId, out var sections) && sections.Remove(EnsureKey(sectionId))) @@ -163,7 +163,7 @@ internal sealed class SettingsService : ISettingsService document.Sections.Remove(pluginId); } - PersistPluginDocumentLocked(document); + PersistAirAppDocumentLocked(document); } } @@ -171,7 +171,7 @@ internal sealed class SettingsService : ISettingsService } public T? GetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, string? subjectId = null, string? placementId = null, @@ -179,17 +179,17 @@ internal sealed class SettingsService : ISettingsService { var snapshot = scope switch { - SettingsScope.App => JsonSerializer.SerializeToElement(_appSettingsService.Load(), SerializerOptions), - SettingsScope.Launcher => JsonSerializer.SerializeToElement(_launcherSettingsService.Load(), SerializerOptions), - SettingsScope.ComponentInstance => JsonSerializer.SerializeToElement( + AirAppSettingsScope.App => JsonSerializer.SerializeToElement(_appSettingsService.Load(), SerializerOptions), + AirAppSettingsScope.Launcher => JsonSerializer.SerializeToElement(_launcherSettingsService.Load(), SerializerOptions), + AirAppSettingsScope.ComponentInstance => JsonSerializer.SerializeToElement( LoadSection>( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, EnsureKey(subjectId), sectionId ?? "__root__", placementId), SerializerOptions), - SettingsScope.Plugin => JsonSerializer.SerializeToElement( - LoadSection>(SettingsScope.Plugin, EnsureKey(subjectId), sectionId ?? "__root__", placementId), + AirAppSettingsScope.AirApp => JsonSerializer.SerializeToElement( + LoadSection>(AirAppSettingsScope.AirApp, EnsureKey(subjectId), sectionId ?? "__root__", placementId), SerializerOptions), _ => default }; @@ -220,7 +220,7 @@ internal sealed class SettingsService : ISettingsService } public void SetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, T value, string? subjectId = null, @@ -228,19 +228,19 @@ internal sealed class SettingsService : ISettingsService string? sectionId = null, IReadOnlyCollection? changedKeys = null) { - if (scope == SettingsScope.Plugin) + if (scope == AirAppSettingsScope.AirApp) { var dict = LoadSection>( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, EnsureKey(subjectId), sectionId ?? "__root__", placementId); dict[key] = JsonSerializer.SerializeToElement(value, SerializerOptions).Clone(); - SaveSection(SettingsScope.Plugin, EnsureKey(subjectId), sectionId ?? "__root__", dict, placementId, changedKeys ?? [key]); + SaveSection(AirAppSettingsScope.AirApp, EnsureKey(subjectId), sectionId ?? "__root__", dict, placementId, changedKeys ?? [key]); return; } - if (scope == SettingsScope.ComponentInstance) + if (scope == AirAppSettingsScope.ComponentInstance) { var effectiveSection = sectionId ?? "__root__"; var dict = _componentMessageStore.LoadSection>(EnsureKey(subjectId), placementId, effectiveSection); @@ -250,7 +250,7 @@ internal sealed class SettingsService : ISettingsService return; } - if (scope == SettingsScope.App) + if (scope == AirAppSettingsScope.App) { var snapshot = _appSettingsService.Load(); var updated = UpdateObjectKey(snapshot, key, value); @@ -259,7 +259,7 @@ internal sealed class SettingsService : ISettingsService return; } - if (scope == SettingsScope.Launcher) + if (scope == AirAppSettingsScope.Launcher) { var snapshot = _launcherSettingsService.Load(); var updated = UpdateObjectKey(snapshot, key, value); @@ -329,26 +329,26 @@ internal sealed class SettingsService : ISettingsService } } - private PluginSettingsDocument LoadPluginDocumentLocked() + private AirAppSettingsDocument LoadAirAppDocumentLocked() { try { if (!File.Exists(_pluginSettingsPath)) { - return new PluginSettingsDocument(); + return new AirAppSettingsDocument(); } var json = File.ReadAllText(_pluginSettingsPath); - return JsonSerializer.Deserialize(json, SerializerOptions) ?? new PluginSettingsDocument(); + return JsonSerializer.Deserialize(json, SerializerOptions) ?? new AirAppSettingsDocument(); } catch (Exception ex) { AppLogger.Warn("SettingsService", $"Failed to load plugin settings '{_pluginSettingsPath}'.", ex); - return new PluginSettingsDocument(); + return new AirAppSettingsDocument(); } } - private void PersistPluginDocumentLocked(PluginSettingsDocument document) + private void PersistAirAppDocumentLocked(AirAppSettingsDocument document) { try { @@ -401,28 +401,28 @@ internal sealed class SettingsService : ISettingsService public string? PlacementId { get; } public T LoadSnapshot() where T : new() - => _settingsService.LoadSnapshot(SettingsScope.ComponentInstance, ComponentId, PlacementId); + => _settingsService.LoadSnapshot(AirAppSettingsScope.ComponentInstance, ComponentId, PlacementId); public void SaveSnapshot(T snapshot, IReadOnlyCollection? changedKeys = null) - => _settingsService.SaveSnapshot(SettingsScope.ComponentInstance, snapshot, ComponentId, PlacementId, changedKeys: changedKeys); + => _settingsService.SaveSnapshot(AirAppSettingsScope.ComponentInstance, snapshot, ComponentId, PlacementId, changedKeys: changedKeys); public T LoadSection(string sectionId) where T : new() - => _settingsService.LoadSection(SettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); + => _settingsService.LoadSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); public void SaveSection(string sectionId, T section, IReadOnlyCollection? changedKeys = null) - => _settingsService.SaveSection(SettingsScope.ComponentInstance, ComponentId, sectionId, section, PlacementId, changedKeys); + => _settingsService.SaveSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, section, PlacementId, changedKeys); public void DeleteSection(string sectionId) - => _settingsService.DeleteSection(SettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); + => _settingsService.DeleteSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); public T? GetValue(string key) - => _settingsService.GetValue(SettingsScope.ComponentInstance, key, ComponentId, PlacementId); + => _settingsService.GetValue(AirAppSettingsScope.ComponentInstance, key, ComponentId, PlacementId); public void SetValue(string key, T value, IReadOnlyCollection? changedKeys = null) - => _settingsService.SetValue(SettingsScope.ComponentInstance, key, value, ComponentId, PlacementId, changedKeys: changedKeys); + => _settingsService.SetValue(AirAppSettingsScope.ComponentInstance, key, value, ComponentId, PlacementId, changedKeys: changedKeys); } - private sealed class PluginSettingsDocument + private sealed class AirAppSettingsDocument { public Dictionary> Sections { get; set; } = new(StringComparer.OrdinalIgnoreCase); } diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsServiceAppSnapshotExtensions.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsServiceAppSnapshotExtensions.cs index 5c816ac..4211a91 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsServiceAppSnapshotExtensions.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsServiceAppSnapshotExtensions.cs @@ -1,6 +1,6 @@ using System; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Services; @@ -9,12 +9,12 @@ public static class SettingsServiceAppSnapshotExtensions public static AppSettingsSnapshot Load(this ISettingsService settingsService) { ArgumentNullException.ThrowIfNull(settingsService); - return settingsService.LoadSnapshot(SettingsScope.App); + return settingsService.LoadSnapshot(AirAppSettingsScope.App); } public static void Save(this ISettingsService settingsService, AppSettingsSnapshot snapshot) { ArgumentNullException.ThrowIfNull(settingsService); - settingsService.SaveSnapshot(SettingsScope.App, snapshot ?? new AppSettingsSnapshot()); + settingsService.SaveSnapshot(AirAppSettingsScope.App, snapshot ?? new AppSettingsSnapshot()); } } diff --git a/desktop/LanMountainDesktop/Services/Settings/SettingsWindowService.cs b/desktop/LanMountainDesktop/Services/Settings/SettingsWindowService.cs index 24285f2..b08a7db 100644 --- a/desktop/LanMountainDesktop/Services/Settings/SettingsWindowService.cs +++ b/desktop/LanMountainDesktop/Services/Settings/SettingsWindowService.cs @@ -6,7 +6,7 @@ using Avalonia.Media; using Avalonia.Styling; using Avalonia.Threading; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Theme; using LanMountainDesktop.ViewModels; @@ -214,7 +214,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService { _ = sender; - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } @@ -276,7 +276,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService return; } - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var devPageVisible = _pageRegistry.GetPages().Any(p => p.PageId == "dev"); if (snapshot.IsDevModeEnabled && !devPageVisible) diff --git a/desktop/LanMountainDesktop/Services/SettingsSearchService.cs b/desktop/LanMountainDesktop/Services/SettingsSearchService.cs index 4c21a7f..9d8be6e 100644 --- a/desktop/LanMountainDesktop/Services/SettingsSearchService.cs +++ b/desktop/LanMountainDesktop/Services/SettingsSearchService.cs @@ -204,7 +204,7 @@ internal sealed class SettingsSearchService [ descriptor.Category.ToString(), descriptor.IconKey, - descriptor.PluginId ?? string.Empty, + descriptor.AirAppId ?? string.Empty, descriptor.GroupId ?? string.Empty ]); } diff --git a/desktop/LanMountainDesktop/Services/TelemetryEventNames.cs b/desktop/LanMountainDesktop/Services/TelemetryEventNames.cs index a4185f0..14c15c2 100644 --- a/desktop/LanMountainDesktop/Services/TelemetryEventNames.cs +++ b/desktop/LanMountainDesktop/Services/TelemetryEventNames.cs @@ -25,10 +25,10 @@ internal static class TelemetryEventNames internal const string DesktopComponentDeleted = "desktop_component_deleted"; internal const string DesktopComponentEditorOpened = "desktop_component_editor_opened"; internal const string ThemeChanged = "theme_changed"; - internal const string PluginInstalled = "plugin_installed"; - internal const string PluginUninstalled = "plugin_uninstalled"; - internal const string PluginEnabled = "plugin_enabled"; - internal const string PluginDisabled = "plugin_disabled"; + internal const string AirAppInstalled = "plugin_installed"; + internal const string AirAppUninstalled = "plugin_uninstalled"; + internal const string AirAppEnabled = "plugin_enabled"; + internal const string AirAppDisabled = "plugin_disabled"; internal const string UpdateChecked = "update_checked"; internal const string UpdateInstalled = "update_installed"; internal const string AppCrash = "app_crash"; @@ -55,10 +55,10 @@ internal static class TelemetryEventNames [DesktopComponentDeleted] = "桌面组件删除", [DesktopComponentEditorOpened] = "组件编辑器打开", [ThemeChanged] = "主题变更", - [PluginInstalled] = "插件安装", - [PluginUninstalled] = "插件卸载", - [PluginEnabled] = "插件启用", - [PluginDisabled] = "插件禁用", + [AirAppInstalled] = "插件安装", + [AirAppUninstalled] = "插件卸载", + [AirAppEnabled] = "插件启用", + [AirAppDisabled] = "插件禁用", [UpdateChecked] = "更新检查", [UpdateInstalled] = "更新安装", [AppCrash] = "应用崩溃", diff --git a/desktop/LanMountainDesktop/Services/TelemetryIdentityService.cs b/desktop/LanMountainDesktop/Services/TelemetryIdentityService.cs index 0d19171..bd556c4 100644 --- a/desktop/LanMountainDesktop/Services/TelemetryIdentityService.cs +++ b/desktop/LanMountainDesktop/Services/TelemetryIdentityService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; namespace LanMountainDesktop.Services; @@ -89,7 +89,7 @@ public sealed class TelemetryIdentityService return false; } - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); if (snapshot.HasReportedTelemetryBaseline) { _hasReportedBaseline = true; @@ -98,7 +98,7 @@ public sealed class TelemetryIdentityService snapshot.HasReportedTelemetryBaseline = true; _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [nameof(AppSettingsSnapshot.HasReportedTelemetryBaseline)]); @@ -112,7 +112,7 @@ public sealed class TelemetryIdentityService { lock (_syncRoot) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var changedKeys = new List(); if (string.IsNullOrWhiteSpace(snapshot.TelemetryInstallId)) @@ -134,7 +134,7 @@ public sealed class TelemetryIdentityService if (changedKeys.Count > 0) { _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: changedKeys); } diff --git a/desktop/LanMountainDesktop/ViewModels/PluginCatalogSettingsPageViewModels.cs b/desktop/LanMountainDesktop/ViewModels/AirAppCatalogSettingsPageViewModels.cs similarity index 78% rename from desktop/LanMountainDesktop/ViewModels/PluginCatalogSettingsPageViewModels.cs rename to desktop/LanMountainDesktop/ViewModels/AirAppCatalogSettingsPageViewModels.cs index 951a6b1..d04b9bc 100644 --- a/desktop/LanMountainDesktop/ViewModels/PluginCatalogSettingsPageViewModels.cs +++ b/desktop/LanMountainDesktop/ViewModels/AirAppCatalogSettingsPageViewModels.cs @@ -8,14 +8,14 @@ using Avalonia.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FluentIcons.Common; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; -using LanMountainDesktop.Services.PluginMarket; +using LanMountainDesktop.Services.AirAppMarket; using LanMountainDesktop.Services.Settings; namespace LanMountainDesktop.ViewModels; -public enum PluginCatalogPrimaryActionState +public enum AirAppCatalogPrimaryActionState { Install, Update, @@ -24,14 +24,14 @@ public enum PluginCatalogPrimaryActionState Incompatible } -public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposable +public sealed partial class AirAppCatalogItemViewModel : ViewModelBase, IDisposable { private readonly LocalizationService _localizationService; private readonly string _languageCode; private bool _isLoadingIcon; - public PluginCatalogItemViewModel( - PluginCatalogItemInfo plugin, + public AirAppCatalogItemViewModel( + AirAppCatalogItemInfo plugin, LocalizationService localizationService, string languageCode) { @@ -46,9 +46,9 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa ActionTooltip = L("market.button.install", "Install"); } - public PluginCatalogItemInfo Info { get; } + public AirAppCatalogItemInfo Info { get; } - public string PluginId => Info.Id; + public string AirAppId => Info.Id; public string Name => Info.Name; @@ -64,11 +64,11 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa public string ReadmeUrl => Info.ReadmeUrl; - public IReadOnlyList Dependencies => Info.SharedContracts; + public IReadOnlyList Dependencies => Info.SharedContracts; - public IReadOnlyList PackageSources => Info.PackageSources; + public IReadOnlyList PackageSources => Info.PackageSources; - public IReadOnlyList Capabilities => Info.Capabilities; + public IReadOnlyList Capabilities => Info.Capabilities; public string IconFallbackText { get; } @@ -104,7 +104,7 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa public bool HasIcon => IconBitmap is not null; - public PluginCatalogPrimaryActionState ActionState { get; private set; } + public AirAppCatalogPrimaryActionState ActionState { get; private set; } partial void OnIconBitmapChanged(Bitmap? value) { @@ -144,19 +144,19 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa RefreshActionPresentation(); } - public void ApplyInstallState(InstalledPluginInfo? installedPlugin, Version? hostVersion, bool hasPendingRestart = false) + public void ApplyInstallState(AirAppInstalledInfo? installedAirApp, Version? hostVersion, bool hasPendingRestart = false) { var isCompatible = hostVersion is null || !System.Version.TryParse(MinHostVersion, out var minHostVersion) || hostVersion >= minHostVersion; - var isInstalled = installedPlugin is not null; - var isUpdateAvailable = installedPlugin is not null && CompareVersions(Version, installedPlugin.Manifest.Version) > 0; + var isInstalled = installedAirApp is not null; + var isUpdateAvailable = installedAirApp is not null && CompareVersions(Version, installedAirApp.Manifest.Version) > 0; var requiresRestart = hasPendingRestart || - (installedPlugin is not null && - installedPlugin.IsEnabled && - !installedPlugin.IsLoaded && - string.IsNullOrWhiteSpace(installedPlugin.ErrorMessage)); + (installedAirApp is not null && + installedAirApp.IsEnabled && + !installedAirApp.IsLoaded && + string.IsNullOrWhiteSpace(installedAirApp.ErrorMessage)); IsCompatibleWithHost = isCompatible; IsInstalled = isInstalled; @@ -170,7 +170,7 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa { if (IsInstalling) { - ActionState = IsUpdateAvailable ? PluginCatalogPrimaryActionState.Update : PluginCatalogPrimaryActionState.Install; + ActionState = IsUpdateAvailable ? AirAppCatalogPrimaryActionState.Update : AirAppCatalogPrimaryActionState.Install; ActionSymbol = Symbol.ArrowClockwise; ActionTooltip = L("market.button.installing", "Installing..."); IsActionEnabled = false; @@ -179,7 +179,7 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa if (!IsCompatibleWithHost) { - ActionState = PluginCatalogPrimaryActionState.Incompatible; + ActionState = AirAppCatalogPrimaryActionState.Incompatible; ActionSymbol = Symbol.Warning; ActionTooltip = string.Format( CultureInfo.CurrentCulture, @@ -191,7 +191,7 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa if (RequiresRestart) { - ActionState = PluginCatalogPrimaryActionState.RestartRequired; + ActionState = AirAppCatalogPrimaryActionState.RestartRequired; ActionSymbol = Symbol.ArrowClockwise; ActionTooltip = L("market.button.restart", "Restart to apply"); IsActionEnabled = true; @@ -200,7 +200,7 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa if (IsUpdateAvailable) { - ActionState = PluginCatalogPrimaryActionState.Update; + ActionState = AirAppCatalogPrimaryActionState.Update; ActionSymbol = Symbol.ArrowSync; ActionTooltip = L("market.button.update", "Update"); IsActionEnabled = true; @@ -209,14 +209,14 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa if (IsInstalled) { - ActionState = PluginCatalogPrimaryActionState.Installed; + ActionState = AirAppCatalogPrimaryActionState.Installed; ActionSymbol = Symbol.CheckmarkCircle; ActionTooltip = L("market.button.installed", "Installed"); IsActionEnabled = false; return; } - ActionState = PluginCatalogPrimaryActionState.Install; + ActionState = AirAppCatalogPrimaryActionState.Install; ActionSymbol = Symbol.ArrowDownload; ActionTooltip = L("market.button.install", "Install"); IsActionEnabled = true; @@ -248,20 +248,20 @@ public sealed partial class PluginCatalogItemViewModel : ViewModelBase, IDisposa => _localizationService.GetString(_languageCode, key, fallback); } -public sealed partial class PluginCatalogDetailViewModel : ViewModelBase +public sealed partial class AirAppCatalogDetailViewModel : ViewModelBase { private readonly LocalizationService _localizationService; private readonly string _languageCode; private readonly AirAppMarketReadmeService _readmeService; - private readonly Func _primaryActionAsync; + private readonly Func _primaryActionAsync; private bool _isInitialized; - public PluginCatalogDetailViewModel( - PluginCatalogItemViewModel item, + public AirAppCatalogDetailViewModel( + AirAppCatalogItemViewModel item, LocalizationService localizationService, string languageCode, AirAppMarketReadmeService readmeService, - Func primaryActionAsync) + Func primaryActionAsync) { Item = item; _localizationService = localizationService; @@ -269,7 +269,7 @@ public sealed partial class PluginCatalogDetailViewModel : ViewModelBase _readmeService = readmeService; _primaryActionAsync = primaryActionAsync; - Dependencies = new ObservableCollection(item.Dependencies); + Dependencies = new ObservableCollection(item.Dependencies); VersionLabel = L("market.detail.version", "Version"); PublisherLabel = L("market.detail.author", "Author"); ApiVersionLabel = L("market.detail.api_version", "API Version"); @@ -279,9 +279,9 @@ public sealed partial class PluginCatalogDetailViewModel : ViewModelBase EmptyDependenciesText = L("market.detail.dependencies_empty", "No dependencies were declared by this plugin."); } - public PluginCatalogItemViewModel Item { get; } + public AirAppCatalogItemViewModel Item { get; } - public ObservableCollection Dependencies { get; } + public ObservableCollection Dependencies { get; } public string DrawerTitle => Item.Name; @@ -316,9 +316,9 @@ public sealed partial class PluginCatalogDetailViewModel : ViewModelBase public bool HasReadmeContent => !IsReadmeLoading && !HasReadmeError && !string.IsNullOrWhiteSpace(ReadmeMarkdown); - public IReadOnlyList PackageSources => Item.PackageSources; + public IReadOnlyList PackageSources => Item.PackageSources; - public IReadOnlyList Capabilities => Item.Capabilities; + public IReadOnlyList Capabilities => Item.Capabilities; public async Task InitializeAsync() { @@ -381,28 +381,28 @@ public sealed partial class PluginCatalogDetailViewModel : ViewModelBase => _localizationService.GetString(_languageCode, key, fallback); } -public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, IDisposable +public sealed partial class AirAppCatalogSettingsPageViewModel : ViewModelBase, IDisposable { private readonly ISettingsFacadeService _settingsFacade; - private readonly IPluginCatalogSettingsService _pluginCatalog; + private readonly IAirAppCatalogSettingsService _pluginCatalog; private readonly LocalizationService _localizationService; private readonly AirAppMarketIconService _iconService; private readonly AirAppMarketReadmeService _readmeService; private readonly string _languageCode; - private readonly Dictionary _installedPlugins = new(StringComparer.OrdinalIgnoreCase); - private readonly HashSet _pendingRestartPluginIds = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _installedAirApps = new(StringComparer.OrdinalIgnoreCase); + private readonly HashSet _pendingRestartAirAppIds = new(StringComparer.OrdinalIgnoreCase); private readonly Version? _hostVersion; private bool _isInitialized; private bool _hasLoadedCatalog; - public PluginCatalogSettingsPageViewModel( + public AirAppCatalogSettingsPageViewModel( ISettingsFacadeService settingsFacade, LocalizationService localizationService, AirAppMarketIconService iconService, AirAppMarketReadmeService readmeService) { _settingsFacade = settingsFacade; - _pluginCatalog = _settingsFacade.PluginCatalog; + _pluginCatalog = _settingsFacade.AirAppCatalog; _localizationService = localizationService; _iconService = iconService; _readmeService = readmeService; @@ -414,11 +414,11 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, public event Action? RestartRequested; - public event Action? DetailsRequested; + public event Action? DetailsRequested; - public ObservableCollection CatalogPlugins { get; } = []; + public ObservableCollection CatalogAirApps { get; } = []; - public ObservableCollection FilteredPlugins { get; } = []; + public ObservableCollection FilteredAirApps { get; } = []; [ObservableProperty] private string _statusMessage = string.Empty; @@ -463,20 +463,20 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, public void Dispose() { - foreach (var item in CatalogPlugins) + foreach (var item in CatalogAirApps) { item.Dispose(); } - CatalogPlugins.Clear(); - FilteredPlugins.Clear(); + CatalogAirApps.Clear(); + FilteredAirApps.Clear(); _iconService.Dispose(); _readmeService.Dispose(); } - public PluginCatalogDetailViewModel CreateDetailViewModel(PluginCatalogItemViewModel item) + public AirAppCatalogDetailViewModel CreateDetailViewModel(AirAppCatalogItemViewModel item) { - return new PluginCatalogDetailViewModel( + return new AirAppCatalogDetailViewModel( item, _localizationService, _languageCode, @@ -502,8 +502,8 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, if (!result.Success) { _hasLoadedCatalog = false; - CatalogPlugins.Clear(); - FilteredPlugins.Clear(); + CatalogAirApps.Clear(); + FilteredAirApps.Clear(); ShowEmptyState = true; EmptyStateText = string.IsNullOrWhiteSpace(result.ErrorMessage) ? L("market.list.empty", "The plugin catalog has not been loaded yet.") @@ -518,12 +518,12 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, } _hasLoadedCatalog = true; - CatalogPlugins.Clear(); - foreach (var plugin in result.Plugins) + CatalogAirApps.Clear(); + foreach (var plugin in result.AirApps) { - var item = new PluginCatalogItemViewModel(plugin, _localizationService, _languageCode); - item.ApplyInstallState(ResolveInstalledPlugin(plugin.Id), _hostVersion); - CatalogPlugins.Add(item); + var item = new AirAppCatalogItemViewModel(plugin, _localizationService, _languageCode); + item.ApplyInstallState(ResolveInstalledAirApp(plugin.Id), _hostVersion); + CatalogAirApps.Add(item); _ = item.EnsureIconLoadedAsync(_iconService); } @@ -533,12 +533,12 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, ? string.Format( CultureInfo.CurrentCulture, L("market.status.loaded_cache_format", "Official source unavailable. Loaded {0} plugin(s) from cache. Reason: {1}"), - CatalogPlugins.Count, + CatalogAirApps.Count, result.WarningMessage ?? L("market.detail.unknown", "Unknown")) : string.Format( CultureInfo.CurrentCulture, L("market.status.loaded_network_format", "Loaded {0} plugin(s) from the official source."), - CatalogPlugins.Count); + CatalogAirApps.Count); } finally { @@ -547,7 +547,7 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, } [RelayCommand] - private void OpenDetails(PluginCatalogItemViewModel? item) + private void OpenDetails(AirAppCatalogItemViewModel? item) { if (item is null) { @@ -558,19 +558,19 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, } [RelayCommand] - private Task ExecutePrimaryActionAsync(PluginCatalogItemViewModel? item) + private Task ExecutePrimaryActionAsync(AirAppCatalogItemViewModel? item) { return item is null ? Task.CompletedTask : ExecutePrimaryActionCoreAsync(item); } - private async Task ExecutePrimaryActionCoreAsync(PluginCatalogItemViewModel item) + private async Task ExecutePrimaryActionCoreAsync(AirAppCatalogItemViewModel item) { if (item.IsInstalling) { return; } - if (item.ActionState == PluginCatalogPrimaryActionState.RestartRequired) + if (item.ActionState == AirAppCatalogPrimaryActionState.RestartRequired) { RestartRequested?.Invoke(RestartRequiredMessage); return; @@ -589,24 +589,24 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, L("market.status.installing_format", "Downloading and staging plugin '{0}'..."), item.Name); - var result = await _pluginCatalog.InstallAsync(item.PluginId); + var result = await _pluginCatalog.InstallAsync(item.AirAppId); if (result.Success) { - _pendingRestartPluginIds.Add(result.PluginId ?? item.PluginId); + _pendingRestartAirAppIds.Add(result.AirAppId ?? item.AirAppId); RefreshInstalledSnapshot(); RefreshItemStates(); // 设置更明显的状态消息 - var pluginName = result.PluginName ?? item.Name; + var pluginName = result.AirAppName ?? item.Name; StatusMessage = string.Format( CultureInfo.CurrentCulture, - L("market.status.install_success_restart_format", "Plugin '{0}' has been staged. Restart the app to apply it."), + L("market.status.install_success_restart_format", "AirApp '{0}' has been staged. Restart the app to apply it."), pluginName); // 触发重启提醒 RestartRequested?.Invoke(string.Format( CultureInfo.CurrentCulture, - L("market.dialog.restart_message_format", "Plugin '{0}' has been installed successfully.\n\nTo use this plugin, you need to restart the application now.\n\nWould you like to restart?"), + L("market.dialog.restart_message_format", "AirApp '{0}' has been installed successfully.\n\nTo use this plugin, you need to restart the application now.\n\nWould you like to restart?"), pluginName)); return; } @@ -635,12 +635,12 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, private void RefreshItemStates() { - foreach (var item in CatalogPlugins) + foreach (var item in CatalogAirApps) { item.ApplyInstallState( - ResolveInstalledPlugin(item.PluginId), + ResolveInstalledAirApp(item.AirAppId), _hostVersion, - _pendingRestartPluginIds.Contains(item.PluginId)); + _pendingRestartAirAppIds.Contains(item.AirAppId)); } ApplyFilter(); @@ -648,25 +648,25 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, private void RefreshInstalledSnapshot() { - _installedPlugins.Clear(); - foreach (var plugin in _settingsFacade.PluginManagement.GetInstalledPlugins()) + _installedAirApps.Clear(); + foreach (var plugin in _settingsFacade.AirAppManagement.GetInstalledAirApps()) { - _installedPlugins[plugin.Manifest.Id] = plugin; + _installedAirApps[plugin.Manifest.Id] = plugin; } } - private InstalledPluginInfo? ResolveInstalledPlugin(string pluginId) + private AirAppInstalledInfo? ResolveInstalledAirApp(string pluginId) { - return _installedPlugins.TryGetValue(pluginId, out var installedPlugin) - ? installedPlugin + return _installedAirApps.TryGetValue(pluginId, out var installedAirApp) + ? installedAirApp : null; } private void ApplyFilter() { - FilteredPlugins.Clear(); + FilteredAirApps.Clear(); - IEnumerable filtered = CatalogPlugins; + IEnumerable filtered = CatalogAirApps; var query = SearchText?.Trim(); if (!string.IsNullOrWhiteSpace(query)) { @@ -674,16 +674,16 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, item.Name.Contains(query, StringComparison.OrdinalIgnoreCase) || item.Description.Contains(query, StringComparison.OrdinalIgnoreCase) || item.Author.Contains(query, StringComparison.OrdinalIgnoreCase) || - item.PluginId.Contains(query, StringComparison.OrdinalIgnoreCase) || + item.AirAppId.Contains(query, StringComparison.OrdinalIgnoreCase) || item.Info.Tags.Any(tag => tag.Contains(query, StringComparison.OrdinalIgnoreCase))); } foreach (var item in filtered) { - FilteredPlugins.Add(item); + FilteredAirApps.Add(item); } - ShowEmptyState = FilteredPlugins.Count == 0; + ShowEmptyState = FilteredAirApps.Count == 0; EmptyStateText = !_hasLoadedCatalog ? L("market.list.empty", "The plugin catalog has not been loaded yet.") : string.IsNullOrWhiteSpace(query) @@ -693,11 +693,11 @@ public sealed partial class PluginCatalogSettingsPageViewModel : ViewModelBase, private void RefreshLocalizedText() { - PageTitle = L("settings.plugin_catalog.title", "Plugin Catalog"); + PageTitle = L("settings.plugin_catalog.title", "AirApp Catalog"); PageDescription = L("settings.plugin_catalog.subtitle", "Browse plugins from the official LanAirApp source and stage installs."); SearchPlaceholder = L("market.toolbar.search_placeholder", "Search plugins"); RefreshButtonText = L("market.toolbar.refresh", "Refresh"); - RestartRequiredMessage = L("settings.plugins.restart_required", "Plugin changes take effect after restart."); + RestartRequiredMessage = L("settings.plugins.restart_required", "AirApp changes take effect after restart."); EmptyStateText = L("market.list.empty", "The plugin catalog has not been loaded yet."); } diff --git a/desktop/LanMountainDesktop/ViewModels/LauncherSettingsPageViewModel.cs b/desktop/LanMountainDesktop/ViewModels/LauncherSettingsPageViewModel.cs index 1480737..66f60ff 100644 --- a/desktop/LanMountainDesktop/ViewModels/LauncherSettingsPageViewModel.cs +++ b/desktop/LanMountainDesktop/ViewModels/LauncherSettingsPageViewModel.cs @@ -9,7 +9,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FluentIcons.Common; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -142,7 +142,7 @@ public sealed partial class LauncherSettingsPageViewModel : ViewModelBase, IDisp var snapshot = _settingsFacade.LauncherPolicy.Get()?.Clone() ?? new LauncherSettingsSnapshot(); snapshot.ShowTileBackground = value; _settingsFacade.Settings.SaveSnapshot( - SettingsScope.Launcher, + AirAppSettingsScope.Launcher, snapshot, changedKeys: [nameof(LauncherSettingsSnapshot.ShowTileBackground)]); } @@ -160,7 +160,7 @@ public sealed partial class LauncherSettingsPageViewModel : ViewModelBase, IDisp private void OnSettingsChanged(object? sender, SettingsChangedEvent e) { - if (e.Scope != SettingsScope.Launcher) + if (e.Scope != AirAppSettingsScope.Launcher) { return; } @@ -333,7 +333,7 @@ public sealed partial class LauncherSettingsPageViewModel : ViewModelBase, IDisp return; } - _settingsFacade.Settings.SaveSnapshot(SettingsScope.Launcher, snapshot, changedKeys: changedKeys); + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.Launcher, snapshot, changedKeys: changedKeys); ReloadData(); } diff --git a/desktop/LanMountainDesktop/ViewModels/MusicControlViewModel.cs b/desktop/LanMountainDesktop/ViewModels/MusicControlViewModel.cs index d9c1493..38b2207 100644 --- a/desktop/LanMountainDesktop/ViewModels/MusicControlViewModel.cs +++ b/desktop/LanMountainDesktop/ViewModels/MusicControlViewModel.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Avalonia.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; diff --git a/desktop/LanMountainDesktop/ViewModels/NotificationSettingsPageViewModel.cs b/desktop/LanMountainDesktop/ViewModels/NotificationSettingsPageViewModel.cs index 3b95e3f..bb4a004 100644 --- a/desktop/LanMountainDesktop/ViewModels/NotificationSettingsPageViewModel.cs +++ b/desktop/LanMountainDesktop/ViewModels/NotificationSettingsPageViewModel.cs @@ -4,7 +4,7 @@ using System.Linq; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -38,7 +38,7 @@ public sealed partial class NotificationSettingsPageViewModel : ViewModelBase private void LoadSettings() { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); _isInitializing = true; @@ -67,7 +67,7 @@ public sealed partial class NotificationSettingsPageViewModel : ViewModelBase { if (_isInitializing) return; - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); snapshot.NotificationEnabled = IsNotificationEnabled; snapshot.NotificationDefaultPosition = SelectedPosition?.Value ?? "TopRight"; @@ -80,7 +80,7 @@ public sealed partial class NotificationSettingsPageViewModel : ViewModelBase snapshot.NotificationBoxLinuxCaptureMode = SelectedLinuxCaptureMode?.Value ?? "ProxyDaemon"; _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ diff --git a/desktop/LanMountainDesktop/ViewModels/PrivacyPolicyViewModel.cs b/desktop/LanMountainDesktop/ViewModels/PrivacyPolicyViewModel.cs index 767efd4..28988da 100644 --- a/desktop/LanMountainDesktop/ViewModels/PrivacyPolicyViewModel.cs +++ b/desktop/LanMountainDesktop/ViewModels/PrivacyPolicyViewModel.cs @@ -3,7 +3,7 @@ using System.IO; using System.Reflection; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; namespace LanMountainDesktop.ViewModels; diff --git a/desktop/LanMountainDesktop/ViewModels/PrivacySettingsPageViewModel.cs b/desktop/LanMountainDesktop/ViewModels/PrivacySettingsPageViewModel.cs index f0ace0f..509539a 100644 --- a/desktop/LanMountainDesktop/ViewModels/PrivacySettingsPageViewModel.cs +++ b/desktop/LanMountainDesktop/ViewModels/PrivacySettingsPageViewModel.cs @@ -2,7 +2,7 @@ using System; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; diff --git a/desktop/LanMountainDesktop/ViewModels/SettingsViewModels.cs b/desktop/LanMountainDesktop/ViewModels/SettingsViewModels.cs index c4e0214..9b8c797 100644 --- a/desktop/LanMountainDesktop/ViewModels/SettingsViewModels.cs +++ b/desktop/LanMountainDesktop/ViewModels/SettingsViewModels.cs @@ -14,11 +14,11 @@ using CommunityToolkit.Mvvm.Input; using FluentIcons.Common; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Appearance; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Shared.Contracts.Launcher; namespace LanMountainDesktop.ViewModels; @@ -269,7 +269,7 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo string.Equals(option.Id, regionState.TimeZoneId, StringComparison.OrdinalIgnoreCase)) ?? TimeZones[0]; - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var normalizedRenderMode = AppRenderingModeHelper.Normalize(appSnapshot.AppRenderMode); SelectedRenderMode = RenderModes.FirstOrDefault(option => string.Equals(option.Value, normalizedRenderMode, StringComparison.OrdinalIgnoreCase)) @@ -311,7 +311,7 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo private void OnSettingsChanged(object? sender, SettingsChangedEvent e) { - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } @@ -325,18 +325,18 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo if (changedKeys.Contains(nameof(AppSettingsSnapshot.EnableSlideTransition)) || changedKeys.Contains(nameof(AppSettingsSnapshot.EnableFadeTransition))) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); ApplyTransitionPreferences(snapshot.EnableFadeTransition, snapshot.EnableSlideTransition); } if (changedKeys.Contains(nameof(AppSettingsSnapshot.ShowInTaskbar))) { - ShowInTaskbar = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App).ShowInTaskbar; + ShowInTaskbar = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App).ShowInTaskbar; } if (changedKeys.Contains(nameof(AppSettingsSnapshot.MultiInstanceLaunchBehavior))) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); SelectedMultiInstanceLaunchBehavior = MultiInstanceLaunchBehaviors.FirstOrDefault(option => string.Equals(option.Value, snapshot.MultiInstanceLaunchBehavior.ToString(), StringComparison.OrdinalIgnoreCase)) ?? MultiInstanceLaunchBehaviors.First(option => @@ -345,7 +345,7 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo if (changedKeys.Contains(nameof(AppSettingsSnapshot.BackToWindowsButtonDisplayMode))) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); SelectedBackToWindowsButtonDisplayMode = BackToWindowsButtonDisplayModes.FirstOrDefault(option => string.Equals(option.Value, NormalizeBackToWindowsButtonDisplayMode(snapshot.BackToWindowsButtonDisplayMode), StringComparison.OrdinalIgnoreCase)) ?? BackToWindowsButtonDisplayModes[0]; @@ -355,7 +355,7 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo changedKeys.Contains(nameof(AppSettingsSnapshot.BackToWindowsFluentIconName)) || changedKeys.Contains(nameof(AppSettingsSnapshot.BackToWindowsIconText))) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); SelectedBackToWindowsIconSource = BackToWindowsIconSources.FirstOrDefault(option => string.Equals(option.Value, NormalizeBackToWindowsIconSource(snapshot.BackToWindowsIconSource), StringComparison.OrdinalIgnoreCase)) ?? BackToWindowsIconSources[0]; @@ -567,11 +567,11 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo return; } - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var normalizedRenderMode = AppRenderingModeHelper.Normalize(value.Value); appSnapshot.AppRenderMode = normalizedRenderMode; _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, appSnapshot, changedKeys: [nameof(AppSettingsSnapshot.AppRenderMode)]); @@ -689,25 +689,25 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo private void SaveField(string key, T value) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var property = typeof(AppSettingsSnapshot).GetProperty(key); if (property is not null && property.CanWrite) { property.SetValue(snapshot, value); } - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, snapshot, changedKeys: [key]); + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, snapshot, changedKeys: [key]); } private void SaveTransitionPreferences(bool enableFadeTransition, bool enableSlideTransition) { var normalized = StartupVisualPreferencesResolver.FromFlags(enableFadeTransition, enableSlideTransition); - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); snapshot.EnableFadeTransition = normalized.EnableFadeTransition; snapshot.EnableSlideTransition = normalized.EnableSlideTransition; ApplyTransitionPreferences(normalized.EnableFadeTransition, normalized.EnableSlideTransition); _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ @@ -1359,11 +1359,11 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase => _localizationService.GetString(_languageCode, key, fallback); } -public sealed partial class InstalledPluginItemViewModel : ViewModelBase +public sealed partial class InstalledAirAppItemViewModel : ViewModelBase { - public InstalledPluginItemViewModel(InstalledPluginInfo info) + public InstalledAirAppItemViewModel(AirAppInstalledInfo info) { - PluginId = info.Manifest.Id; + AirAppId = info.Manifest.Id; Name = info.Manifest.Name; Version = info.Manifest.Version ?? "-"; Description = info.Manifest.Description; @@ -1373,7 +1373,7 @@ public sealed partial class InstalledPluginItemViewModel : ViewModelBase IsEnabled = info.IsEnabled; } - public string PluginId { get; } + public string AirAppId { get; } public string Name { get; } @@ -1391,13 +1391,13 @@ public sealed partial class InstalledPluginItemViewModel : ViewModelBase private bool _isEnabled; } -public sealed partial class PluginsSettingsPageViewModel : ViewModelBase +public sealed partial class AirAppsSettingsPageViewModel : ViewModelBase { private readonly ISettingsFacadeService _settingsFacade; private readonly LocalizationService _localizationService = new(); private readonly string _languageCode; - public PluginsSettingsPageViewModel(ISettingsFacadeService settingsFacade) + public AirAppsSettingsPageViewModel(ISettingsFacadeService settingsFacade) { _settingsFacade = settingsFacade; _languageCode = _localizationService.NormalizeLanguageCode(_settingsFacade.Region.Get().LanguageCode); @@ -1409,7 +1409,7 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase public event Action? RestartRequested; - public ObservableCollection InstalledPlugins { get; } = []; + public ObservableCollection InstalledAirApps { get; } = []; [ObservableProperty] private string _statusMessage = string.Empty; @@ -1440,7 +1440,7 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase public async Task InitializeAsync() { - if (InstalledPlugins.Count > 0) + if (InstalledAirApps.Count > 0) { return; } @@ -1460,10 +1460,10 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase { IsBusy = true; - InstalledPlugins.Clear(); - foreach (var plugin in _settingsFacade.PluginManagement.GetInstalledPlugins()) + InstalledAirApps.Clear(); + foreach (var plugin in _settingsFacade.AirAppManagement.GetInstalledAirApps()) { - InstalledPlugins.Add(new InstalledPluginItemViewModel(plugin)); + InstalledAirApps.Add(new InstalledAirAppItemViewModel(plugin)); } StatusMessage = string.Format( @@ -1471,7 +1471,7 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase L( "settings.plugins.refresh_success_installed_format", "Loaded {0} installed plugins."), - InstalledPlugins.Count); + InstalledAirApps.Count); } finally { @@ -1480,20 +1480,20 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase } [RelayCommand] - private void TogglePlugin(InstalledPluginItemViewModel? item) + private void ToggleAirApp(InstalledAirAppItemViewModel? item) { if (item is null) { return; } - if (_settingsFacade.PluginManagement.SetPluginEnabled(item.PluginId, item.IsEnabled)) + if (_settingsFacade.AirAppManagement.SetAirAppEnabled(item.AirAppId, item.IsEnabled)) { StatusMessage = string.Format( CultureInfo.CurrentCulture, L( "settings.plugins.toggle_result_format", - "Plugin '{0}' was {1} for the next launch. Restart the app to apply page and widget changes."), + "AirApp '{0}' was {1} for the next launch. Restart the app to apply page and widget changes."), item.Name, item.IsEnabled ? L("settings.plugins.toggle_state_enabled", "enabled") @@ -1505,27 +1505,27 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase item.IsEnabled = !item.IsEnabled; StatusMessage = string.Format( CultureInfo.CurrentCulture, - L("settings.plugins.toggle_unchanged_format", "Plugin '{0}' did not change."), + L("settings.plugins.toggle_unchanged_format", "AirApp '{0}' did not change."), item.Name); } } [RelayCommand] - private void DeletePlugin(InstalledPluginItemViewModel? item) + private void DeleteAirApp(InstalledAirAppItemViewModel? item) { if (item is null) { return; } - if (_settingsFacade.PluginManagement.DeleteInstalledPlugin(item.PluginId)) + if (_settingsFacade.AirAppManagement.DeleteInstalledAirApp(item.AirAppId)) { - InstalledPlugins.Remove(item); + InstalledAirApps.Remove(item); StatusMessage = string.Format( CultureInfo.CurrentCulture, L( "settings.plugins.delete_success_format", - "Plugin '{0}' was staged for deletion. Restart the app to finish removing it."), + "AirApp '{0}' was staged for deletion. Restart the app to finish removing it."), item.Name); RestartRequested?.Invoke(); } @@ -1540,13 +1540,13 @@ public sealed partial class PluginsSettingsPageViewModel : ViewModelBase private void RefreshLocalizedText() { - PageTitle = L("settings.plugins.title", "Plugins"); + PageTitle = L("settings.plugins.title", "AirApps"); PageDescription = L("settings.plugins.description", "Manage installed plugins and review their runtime state."); - RefreshButtonText = L("settings.plugins.refresh_button", "Refresh Plugins"); - InstalledHeader = L("settings.plugins.installed_header", "Installed Plugins"); + RefreshButtonText = L("settings.plugins.refresh_button", "Refresh AirApps"); + InstalledHeader = L("settings.plugins.installed_header", "Installed AirApps"); DeleteButtonText = L("settings.plugins.delete_button_short", "Delete"); EmptyInstalledText = L("settings.plugins.empty", "No plugins found."); - RestartRequiredMessage = L("settings.plugins.restart_required", "Plugin changes take effect after restart."); + RestartRequiredMessage = L("settings.plugins.restart_required", "AirApp changes take effect after restart."); } private string L(string key, string fallback) @@ -1678,9 +1678,9 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); appSnapshot.StudyEnabled = StudyEnabled; - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, appSnapshot, + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, appSnapshot, changedKeys: [nameof(AppSettingsSnapshot.StudyEnabled)]); } catch (Exception) @@ -1773,10 +1773,10 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); appSnapshot.StudyFrameMs = SamplingRateMs; appSnapshot.StudyScoreThresholdDbfs = NoiseSensitivityDbfs; - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, appSnapshot, + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, appSnapshot, changedKeys: [nameof(AppSettingsSnapshot.StudyFrameMs), nameof(AppSettingsSnapshot.StudyScoreThresholdDbfs)]); UpdateThresholdText(); UpdateStudyAnalyticsConfig(); @@ -1971,14 +1971,14 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); appSnapshot.StudyFocusDurationMinutes = FocusDurationMinutes; appSnapshot.StudyBreakDurationMinutes = BreakDurationMinutes; appSnapshot.StudyLongBreakDurationMinutes = LongBreakDurationMinutes; appSnapshot.StudySessionsBeforeLongBreak = SessionsBeforeLongBreak; appSnapshot.StudyAutoStartBreak = AutoStartBreak; appSnapshot.StudyAutoStartFocus = AutoStartFocus; - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, appSnapshot, + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, appSnapshot, changedKeys: [ nameof(AppSettingsSnapshot.StudyFocusDurationMinutes), nameof(AppSettingsSnapshot.StudyBreakDurationMinutes), @@ -2049,10 +2049,10 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); appSnapshot.StudyNoiseAlertEnabled = NoiseAlertEnabled; appSnapshot.StudyMaxInterruptsPerMinute = MaxInterruptsPerMinute; - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, appSnapshot, + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, appSnapshot, changedKeys: [nameof(AppSettingsSnapshot.StudyNoiseAlertEnabled), nameof(AppSettingsSnapshot.StudyMaxInterruptsPerMinute)]); UpdateStudyAnalyticsConfig(); } @@ -2165,11 +2165,11 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); appSnapshot.StudyShowRealtimeDb = ShowRealtimeDb; appSnapshot.StudyBaselineDb = BaselineDb; appSnapshot.StudyAvgWindowSec = AvgWindowSec; - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, appSnapshot, + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, appSnapshot, changedKeys: [nameof(AppSettingsSnapshot.StudyShowRealtimeDb), nameof(AppSettingsSnapshot.StudyBaselineDb), nameof(AppSettingsSnapshot.StudyAvgWindowSec)]); UpdateStudyAnalyticsConfig(); } @@ -2183,7 +2183,7 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase { try { - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); // Master switch - 确保正确加载保存的值 StudyEnabled = appSnapshot.StudyEnabled; @@ -2315,16 +2315,16 @@ public sealed partial class StudySettingsPageViewModel : ViewModelBase => _localizationService.GetString(_languageCode, key, fallback); } -public sealed class PluginGeneratedSettingsPageViewModel +public sealed class AirAppGeneratedSettingsPageViewModel { - public PluginGeneratedSettingsPageViewModel( + public AirAppGeneratedSettingsPageViewModel( ISettingsService settingsService, string pluginId, - PluginSettingsSectionRegistration section, - PluginLocalizer localizer) + AirAppSettingsSectionRegistration section, + AirAppLocalizer localizer) { SettingsService = settingsService; - PluginId = pluginId; + AirAppId = pluginId; Section = section; Localizer = localizer; Title = localizer.GetString(section.TitleLocalizationKey, section.TitleLocalizationKey); @@ -2335,11 +2335,11 @@ public sealed class PluginGeneratedSettingsPageViewModel public ISettingsService SettingsService { get; } - public string PluginId { get; } + public string AirAppId { get; } - public PluginSettingsSectionRegistration Section { get; } + public AirAppSettingsSectionRegistration Section { get; } - public PluginLocalizer Localizer { get; } + public AirAppLocalizer Localizer { get; } public string Title { get; } @@ -2371,7 +2371,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private bool _isDevModeEnabled; [ObservableProperty] - private string _devPluginPath = string.Empty; + private string _devAirAppPath = string.Empty; [ObservableProperty] private bool _enableThreeFingerSwipe; @@ -2428,13 +2428,13 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private string _desktopLayerConflictCancelText = string.Empty; [ObservableProperty] - private string _pluginPathHeader = string.Empty; + private string _airAppPathHeader = string.Empty; [ObservableProperty] - private string _pluginPathDescription = string.Empty; + private string _airAppPathDescription = string.Empty; [ObservableProperty] - private string _pluginPathPlaceholder = string.Empty; + private string _airAppPathPlaceholder = string.Empty; [ObservableProperty] private string _startupArgsHeader = string.Empty; @@ -2480,9 +2480,9 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase DesktopLayerConflictEnableFusedMessage = L("settings.dev.desktop_layer_conflict_enable_fused", "Fused desktop and main desktop layer mode cannot run at the same time. Enabling fused desktop will turn off main desktop layer mode."); DesktopLayerConflictConfirmText = L("settings.dev.desktop_layer_conflict_confirm", "Switch"); DesktopLayerConflictCancelText = L("settings.dev.desktop_layer_conflict_cancel", "Cancel"); - PluginPathHeader = L("settings.dev.plugin_path_header", "Development plugin path"); - PluginPathDescription = L("settings.dev.plugin_path_description", "Load a local plugin output directory without packaging."); - PluginPathPlaceholder = L("settings.dev.plugin_path_placeholder", "e.g. C:\\path\\to\\plugin\\bin\\Debug\\net10.0"); + AirAppPathHeader = L("settings.dev.plugin_path_header", "Development plugin path"); + AirAppPathDescription = L("settings.dev.plugin_path_description", "Load a local plugin output directory without packaging."); + AirAppPathPlaceholder = L("settings.dev.plugin_path_placeholder", "e.g. C:\\path\\to\\plugin\\bin\\Debug\\net10.0"); StartupArgsHeader = L("settings.dev.startup_args_header", "Developer startup arguments"); StartupArgsDescription = L("settings.dev.startup_args_description", "Command-line arguments and environment variables for development."); CliLabel = L("settings.dev.cli_label", "Command-line arguments:"); @@ -2503,7 +2503,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase SaveField(nameof(AppSettingsSnapshot.IsDevModeEnabled), value); } - partial void OnDevPluginPathChanged(string value) + partial void OnDevAirAppPathChanged(string value) { if (_isInitializing) return; SaveField(nameof(AppSettingsSnapshot.DevPluginPath), value); @@ -2529,9 +2529,9 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private void LoadSettings() { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); IsDevModeEnabled = snapshot.IsDevModeEnabled; - DevPluginPath = snapshot.DevPluginPath ?? string.Empty; + DevAirAppPath = snapshot.DevPluginPath ?? string.Empty; EnableThreeFingerSwipe = snapshot.EnableThreeFingerSwipe; EnableFusedDesktop = snapshot.EnableFusedDesktop; EnableMainWindowDesktopLayer = snapshot.EnableMainWindowDesktopLayer; @@ -2539,7 +2539,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private void OnSettingsChanged(object? sender, SettingsChangedEvent e) { - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } @@ -2553,7 +2553,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase _isInitializing = true; try { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); EnableThreeFingerSwipe = snapshot.EnableThreeFingerSwipe; EnableFusedDesktop = snapshot.EnableFusedDesktop; EnableMainWindowDesktopLayer = snapshot.EnableMainWindowDesktopLayer; @@ -2566,19 +2566,19 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private void SaveField(string key, T value) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var property = typeof(AppSettingsSnapshot).GetProperty(key); if (property is not null && property.CanWrite) { property.SetValue(snapshot, value); } - _settingsFacade.Settings.SaveSnapshot(SettingsScope.App, snapshot, changedKeys: [key]); + _settingsFacade.Settings.SaveSnapshot(AirAppSettingsScope.App, snapshot, changedKeys: [key]); } public void ApplyFusedDesktopPreference(bool enabled, bool disableMainWindowDesktopLayer) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); snapshot.EnableFusedDesktop = enabled; if (enabled && disableMainWindowDesktopLayer) { @@ -2590,7 +2590,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase public void ApplyMainWindowDesktopLayerPreference(bool enabled, bool disableFusedDesktop) { - var snapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); snapshot.EnableMainWindowDesktopLayer = enabled; if (enabled && disableFusedDesktop) { @@ -2603,7 +2603,7 @@ public sealed partial class DevSettingsPageViewModel : ViewModelBase private void SaveDesktopLayerPreferences(AppSettingsSnapshot snapshot) { _settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [ diff --git a/desktop/LanMountainDesktop/Views/Components/AnalogClockWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/AnalogClockWidget.axaml.cs index 3779307..b8d8129 100644 --- a/desktop/LanMountainDesktop/Views/Components/AnalogClockWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/AnalogClockWidget.axaml.cs @@ -10,7 +10,7 @@ using Avalonia.Styling; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -402,9 +402,9 @@ public partial class AnalogClockWidget : UserControl, IDesktopComponentWidget, I private void LoadClockSettings() { - var appSnapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var componentSnapshot = _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, _componentId, _placementId); _languageCode = _localizationService.NormalizeLanguageCode(appSnapshot.LanguageCode); diff --git a/desktop/LanMountainDesktop/Views/Components/BaiduHotSearchWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/BaiduHotSearchWidget.axaml.cs index d506142..598651a 100644 --- a/desktop/LanMountainDesktop/Views/Components/BaiduHotSearchWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/BaiduHotSearchWidget.axaml.cs @@ -35,7 +35,7 @@ public partial class BaiduHotSearchWidget : UserControl, IDesktopComponentWidget Interval = TimeSpan.FromMinutes(15) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly List _activeItems = []; diff --git a/desktop/LanMountainDesktop/Views/Components/BilibiliHotSearchWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/BilibiliHotSearchWidget.axaml.cs index 284b804..143e782 100644 --- a/desktop/LanMountainDesktop/Views/Components/BilibiliHotSearchWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/BilibiliHotSearchWidget.axaml.cs @@ -32,7 +32,7 @@ public partial class BilibiliHotSearchWidget : UserControl, IDesktopComponentWid Interval = TimeSpan.FromMinutes(15) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly List _activeItems = []; diff --git a/desktop/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs index 2c2959b..1319352 100644 --- a/desktop/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs @@ -10,7 +10,7 @@ using Avalonia.Styling; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -342,9 +342,9 @@ public partial class ClassScheduleWidget : UserControl, IDesktopComponentWidget, private void RefreshSchedule() { - var appSettings = _settingsService.LoadSnapshot(SettingsScope.App); + var appSettings = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var componentSettings = _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, _componentId, _placementId); _languageCode = _localizationService.NormalizeLanguageCode(appSettings.LanguageCode); diff --git a/desktop/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs index a088341..068043f 100644 --- a/desktop/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs @@ -44,7 +44,7 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget, }; private readonly bool _isDesignModePreview = Design.IsDesignMode; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly Bitmap?[] _newsBitmaps = new Bitmap?[2]; diff --git a/desktop/LanMountainDesktop/Views/Components/ComponentChromeCornerRadiusHelper.cs b/desktop/LanMountainDesktop/Views/Components/ComponentChromeCornerRadiusHelper.cs index d3a096d..34e05af 100644 --- a/desktop/LanMountainDesktop/Views/Components/ComponentChromeCornerRadiusHelper.cs +++ b/desktop/LanMountainDesktop/Views/Components/ComponentChromeCornerRadiusHelper.cs @@ -1,16 +1,16 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Media; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Views.Components; internal static class ComponentChromeCornerRadiusHelper { - public static double ResolveMainRectangleRadiusValue(ComponentChromeContext? chromeContext = null, double fallback = 24d) + public static double ResolveMainRectangleRadiusValue(AirAppComponentChromeContext? chromeContext = null, double fallback = 24d) { if (chromeContext is not null) { @@ -24,7 +24,7 @@ internal static class ComponentChromeCornerRadiusHelper : Math.Max(0d, fallback); } - public static CornerRadius ResolveMainRectangleRadius(ComponentChromeContext? chromeContext = null, double fallback = 24d) + public static CornerRadius ResolveMainRectangleRadius(AirAppComponentChromeContext? chromeContext = null, double fallback = 24d) { return new CornerRadius(ResolveMainRectangleRadiusValue(chromeContext, fallback)); } @@ -50,55 +50,55 @@ internal static class ComponentChromeCornerRadiusHelper : new CornerRadius(fallback); } - public static double SafeValue(double value, double min, double max, ComponentChromeContext? context = null) + public static double SafeValue(double value, double min, double max, AirAppComponentChromeContext? context = null) { _ = context; return Math.Clamp(value, min, max); } - public static double Scale(double value, double min, double max, ComponentChromeContext? context = null) + public static double Scale(double value, double min, double max, AirAppComponentChromeContext? context = null) { _ = context; return Math.Clamp(value, min, max); } - public static CornerRadius SafeRadius(double value, double min, double max, ComponentChromeContext? context = null) + public static CornerRadius SafeRadius(double value, double min, double max, AirAppComponentChromeContext? context = null) { _ = context; return new CornerRadius(Math.Clamp(value, min, max)); } - public static CornerRadius ScaleRadius(double value, double min, double max, ComponentChromeContext? context = null) + public static CornerRadius ScaleRadius(double value, double min, double max, AirAppComponentChromeContext? context = null) { _ = context; return new CornerRadius(Math.Clamp(value, min, max)); } - public static double Mini(ComponentChromeContext? context = null) + public static double Mini(AirAppComponentChromeContext? context = null) { if (context is not null) return context.CornerRadiusTokens.Micro.TopLeft; return ResolveToken("DesignCornerRadiusMicro", 6).TopLeft; } - public static double Micro(ComponentChromeContext? context = null) + public static double Micro(AirAppComponentChromeContext? context = null) { if (context is not null) return context.CornerRadiusTokens.Micro.TopLeft; return ResolveToken("DesignCornerRadiusMicro", 6).TopLeft; } - public static double Small(ComponentChromeContext? context = null) + public static double Small(AirAppComponentChromeContext? context = null) { if (context is not null) return context.CornerRadiusTokens.Sm.TopLeft; return ResolveToken("DesignCornerRadiusSm", 14).TopLeft; } - public static double Medium(ComponentChromeContext? context = null) + public static double Medium(AirAppComponentChromeContext? context = null) { if (context is not null) return context.CornerRadiusTokens.Md.TopLeft; return ResolveToken("DesignCornerRadiusMd", 20).TopLeft; } - public static double Large(ComponentChromeContext? context = null) + public static double Large(AirAppComponentChromeContext? context = null) { if (context is not null) return context.CornerRadiusTokens.Lg.TopLeft; return ResolveToken("DesignCornerRadiusLg", 28).TopLeft; diff --git a/desktop/LanMountainDesktop/Views/Components/DailyArtworkWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/DailyArtworkWidget.axaml.cs index 56b814a..9d0ef6a 100644 --- a/desktop/LanMountainDesktop/Views/Components/DailyArtworkWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/DailyArtworkWidget.axaml.cs @@ -15,7 +15,7 @@ using Avalonia.Media.Imaging; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -687,7 +687,7 @@ public partial class DailyArtworkWidget : UserControl, IDesktopComponentWidget, { try { - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); _languageCode = _localizationService.NormalizeLanguageCode(snapshot.LanguageCode); } catch @@ -701,7 +701,7 @@ public partial class DailyArtworkWidget : UserControl, IDesktopComponentWidget, try { var snapshot = _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, _componentId, _placementId); return DailyArtworkMirrorSources.Normalize(snapshot.DailyArtworkMirrorSource); diff --git a/desktop/LanMountainDesktop/Views/Components/DailyPoetryWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/DailyPoetryWidget.axaml.cs index 7a82baa..60e1c1c 100644 --- a/desktop/LanMountainDesktop/Views/Components/DailyPoetryWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/DailyPoetryWidget.axaml.cs @@ -53,7 +53,7 @@ public partial class DailyPoetryWidget : UserControl, IDesktopComponentWidget, I Interval = TimeSpan.FromHours(6) }; - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private IRecommendationInfoService _recommendationService = DefaultRecommendationService; diff --git a/desktop/LanMountainDesktop/Views/Components/DailyWord2x2Widget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/DailyWord2x2Widget.axaml.cs index 04555a6..122b8fd 100644 --- a/desktop/LanMountainDesktop/Views/Components/DailyWord2x2Widget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/DailyWord2x2Widget.axaml.cs @@ -32,7 +32,7 @@ public partial class DailyWord2x2Widget : UserControl, IDesktopComponentWidget, Interval = TimeSpan.FromHours(6) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); diff --git a/desktop/LanMountainDesktop/Views/Components/DailyWordWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/DailyWordWidget.axaml.cs index 1bc4d41..9b2e78b 100644 --- a/desktop/LanMountainDesktop/Views/Components/DailyWordWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/DailyWordWidget.axaml.cs @@ -31,7 +31,7 @@ public partial class DailyWordWidget : UserControl, IDesktopComponentWidget, IRe }; private readonly bool _isDesignModePreview = Design.IsDesignMode; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); diff --git a/desktop/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs b/desktop/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs index 3653f28..a5d6b4e 100644 --- a/desktop/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs +++ b/desktop/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Avalonia.Controls; -using LanMountainDesktop.Appearance; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.ComponentSystem; -using LanMountainDesktop.Host.Abstractions; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Views.Components; @@ -63,7 +63,7 @@ public sealed class DesktopComponentRuntimeRegistration string componentId, string? displayNameLocalizationKey, Func controlFactory, - Func? cornerRadiusResolver = null) + Func? cornerRadiusResolver = null) { ArgumentException.ThrowIfNullOrWhiteSpace(componentId); ArgumentNullException.ThrowIfNull(controlFactory); @@ -82,22 +82,22 @@ public sealed class DesktopComponentRuntimeRegistration public Func ControlFactory { get; } - public Func? CornerRadiusResolver { get; } + public Func? CornerRadiusResolver { get; } } public sealed class DesktopComponentRuntimeDescriptor { - private static readonly Func DefaultCornerRadiusResolver = + private static readonly Func DefaultCornerRadiusResolver = chromeContext => ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadiusValue(chromeContext); private readonly Func _controlFactory; - private readonly Func _cornerRadiusResolver; + private readonly Func _cornerRadiusResolver; internal DesktopComponentRuntimeDescriptor( DesktopComponentDefinition definition, string? displayNameLocalizationKey, Func controlFactory, - Func? cornerRadiusResolver) + Func? cornerRadiusResolver) { Definition = definition; DisplayNameLocalizationKey = displayNameLocalizationKey; @@ -131,7 +131,7 @@ public sealed class DesktopComponentRuntimeDescriptor var componentAccessor = settingsService.GetComponentAccessor(Definition.Id, placementId); var componentSettingsStore = new ComponentSettingsService(settingsService); componentSettingsStore.SetScopedComponentContext(Definition.Id, placementId); - var chromeContext = new ComponentChromeContext( + var chromeContext = new AirAppComponentChromeContext( Definition.Id, placementId, cellSize, @@ -184,9 +184,9 @@ public sealed class DesktopComponentRuntimeDescriptor placementAwareComponent.SetComponentPlacementContext(Definition.Id, placementId); } - if (control is IComponentChromeContextAware chromeContextAwareComponent) + if (control is IAirAppComponentChromeContextAware chromeContextAwareComponent) { - chromeContextAwareComponent.SetComponentChromeContext(chromeContext); + chromeContextAwareComponent.SetAirAppComponentChromeContext(chromeContext); } if (control is IDesktopComponentWidget sizedComponent) @@ -217,7 +217,7 @@ public sealed class DesktopComponentRuntimeDescriptor return control; } - public double ResolveCornerRadius(ComponentChromeContext chromeContext) + public double ResolveCornerRadius(AirAppComponentChromeContext chromeContext) { ArgumentNullException.ThrowIfNull(chromeContext); @@ -227,7 +227,7 @@ public sealed class DesktopComponentRuntimeDescriptor public double ResolveCornerRadius(double cellSize) { - return ResolveCornerRadius(new ComponentChromeContext( + return ResolveCornerRadius(new AirAppComponentChromeContext( Definition.Id, null, Math.Max(1, cellSize), diff --git a/desktop/LanMountainDesktop/Views/Components/ExchangeRateCalculatorWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/ExchangeRateCalculatorWidget.axaml.cs index 2316691..acda77c 100644 --- a/desktop/LanMountainDesktop/Views/Components/ExchangeRateCalculatorWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/ExchangeRateCalculatorWidget.axaml.cs @@ -34,7 +34,7 @@ public partial class ExchangeRateCalculatorWidget : UserControl, IDesktopCompone Interval = TimeSpan.FromMinutes(30) }; - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private IRecommendationInfoService _recommendationService = DefaultRecommendationService; private ICalculatorDataService _calculatorDataService = DefaultCalculatorService; diff --git a/desktop/LanMountainDesktop/Views/Components/FileManagerWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/FileManagerWidget.axaml.cs index b6f568b..6457ae3 100644 --- a/desktop/LanMountainDesktop/Views/Components/FileManagerWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/FileManagerWidget.axaml.cs @@ -16,7 +16,7 @@ using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.MacOS; using LanMountainDesktop.Platform.Windows; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; namespace LanMountainDesktop.Views.Components; diff --git a/desktop/LanMountainDesktop/Views/Components/IfengNewsWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/IfengNewsWidget.axaml.cs index 2be11c5..977c304 100644 --- a/desktop/LanMountainDesktop/Views/Components/IfengNewsWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/IfengNewsWidget.axaml.cs @@ -43,7 +43,7 @@ public partial class IfengNewsWidget : UserControl, IDesktopComponentWidget, IRe Interval = TimeSpan.FromMinutes(20) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly Dictionary _newsByUrl = new(StringComparer.OrdinalIgnoreCase); diff --git a/desktop/LanMountainDesktop/Views/Components/NotificationBoxWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/NotificationBoxWidget.axaml.cs index c4d640b..5db0717 100644 --- a/desktop/LanMountainDesktop/Views/Components/NotificationBoxWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/NotificationBoxWidget.axaml.cs @@ -10,7 +10,7 @@ using Avalonia.Styling; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -137,7 +137,7 @@ public partial class NotificationBoxWidget : UserControl, { var appSettingsFacade = HostSettingsFacadeProvider.GetOrCreate(); _appSettingsService = appSettingsFacade.Settings; - _appSettings = _appSettingsService.LoadSnapshot(SettingsScope.App); + _appSettings = _appSettingsService.LoadSnapshot(AirAppSettingsScope.App); _isPrivacyMode = _appSettings.NotificationBoxPrivacyMode; _componentSettingsSnapshot = _componentSettings?.Load() diff --git a/desktop/LanMountainDesktop/Views/Components/RecordingWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/RecordingWidget.axaml.cs index 940297d..91ca9c5 100644 --- a/desktop/LanMountainDesktop/Views/Components/RecordingWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/RecordingWidget.axaml.cs @@ -26,7 +26,7 @@ public partial class RecordingWidget : UserControl, IDesktopComponentWidget, IDe private readonly IAudioRecorderService _audioRecorderService = AudioRecorderServiceFactory.CreateRecorder(); private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly List _waveBars = []; private readonly double[] _waveLevels = new double[WaveBarCount]; diff --git a/desktop/LanMountainDesktop/Views/Components/RemovableStorageWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/RemovableStorageWidget.axaml.cs index 50f10cb..0f2a3f6 100644 --- a/desktop/LanMountainDesktop/Views/Components/RemovableStorageWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/RemovableStorageWidget.axaml.cs @@ -11,7 +11,7 @@ using Avalonia.Threading; using FluentIcons.Avalonia; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Theme; @@ -256,7 +256,7 @@ public partial class RemovableStorageWidget : UserControl, IDesktopComponentWidg { try { - var appSettings = _settingsService.LoadSnapshot(SettingsScope.App); + var appSettings = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var componentSettings = _componentSettingsStore.LoadForComponent(_componentId, _placementId); _languageCode = _localizationService.NormalizeLanguageCode(appSettings.LanguageCode); _componentColorScheme = componentSettings.ColorSchemeSource; diff --git a/desktop/LanMountainDesktop/Views/Components/RssReaderWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/RssReaderWidget.axaml.cs index 0c19382..2b6861f 100644 --- a/desktop/LanMountainDesktop/Views/Components/RssReaderWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/RssReaderWidget.axaml.cs @@ -7,7 +7,7 @@ using Avalonia.Threading; using System.Globalization; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.RssReader; using LanMountainDesktop.Services.Settings; diff --git a/desktop/LanMountainDesktop/Views/Components/ShortcutWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/ShortcutWidget.axaml.cs index 638b86f..e6c2edf 100644 --- a/desktop/LanMountainDesktop/Views/Components/ShortcutWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/ShortcutWidget.axaml.cs @@ -13,7 +13,7 @@ using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.MacOS; using LanMountainDesktop.Platform.Windows; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; namespace LanMountainDesktop.Views.Components; diff --git a/desktop/LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml.cs index 2d11043..9c13a91 100644 --- a/desktop/LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml.cs @@ -11,7 +11,7 @@ using Avalonia.Styling; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Theme; @@ -440,9 +440,9 @@ public partial class StandbyDigitalClockWidget : UserControl, private void LoadClockSettings() { - var appSnapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var componentSnapshot = _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, _componentId, _placementId); diff --git a/desktop/LanMountainDesktop/Views/Components/Stcn24ForumWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/Stcn24ForumWidget.axaml.cs index 961b5a5..ba36415 100644 --- a/desktop/LanMountainDesktop/Views/Components/Stcn24ForumWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/Stcn24ForumWidget.axaml.cs @@ -44,7 +44,7 @@ public partial class Stcn24ForumWidget : UserControl, IDesktopComponentWidget, I Interval = TimeSpan.FromMinutes(20) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly List _activeItems = []; diff --git a/desktop/LanMountainDesktop/Views/Components/StickyNoteWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StickyNoteWidget.axaml.cs index 1b92997..e48467e 100644 --- a/desktop/LanMountainDesktop/Views/Components/StickyNoteWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StickyNoteWidget.axaml.cs @@ -9,9 +9,9 @@ using Avalonia.Styling; using Avalonia.Threading; using FluentIcons.Common; using LanMountainDesktop.ComponentSystem; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services.Settings; namespace LanMountainDesktop.Views.Components; @@ -70,12 +70,12 @@ public partial class StickyNoteWidget : UserControl, RootBorder.CornerRadius = new CornerRadius( ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadiusValue( - new ComponentChromeContext( + new AirAppComponentChromeContext( _componentId, _placementId, Math.Max(1, cellSize), - Appearance.AppearanceCornerRadiusTokenFactory.Create( - Settings.Core.GlobalAppearanceSettings.DefaultCornerRadiusStyle)))); + AirAppSdk.AppearanceCornerRadiusTokenFactory.Create( + AirAppSdk.GlobalAppearanceSettings.DefaultCornerRadiusStyle)))); RootBorder.Padding = new Thickness( Math.Clamp(2 * scale, 1, 4), diff --git a/desktop/LanMountainDesktop/Views/Components/StudyDeductionReasonsWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyDeductionReasonsWidget.axaml.cs index 80dbd37..b95e71e 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyDeductionReasonsWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyDeductionReasonsWidget.axaml.cs @@ -39,7 +39,7 @@ public partial class StudyDeductionReasonsWidget : UserControl, IDesktopComponen private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudyEnvironmentWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyEnvironmentWidget.axaml.cs index 003d209..cf5fb42 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyEnvironmentWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyEnvironmentWidget.axaml.cs @@ -13,7 +13,7 @@ public partial class StudyEnvironmentWidget : UserControl, IDesktopComponentWidg { private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsService = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudyInterruptDensityWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyInterruptDensityWidget.axaml.cs index 7433d56..1450bd7 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyInterruptDensityWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyInterruptDensityWidget.axaml.cs @@ -38,7 +38,7 @@ public partial class StudyInterruptDensityWidget : UserControl, IDesktopComponen private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudyNoiseCurveWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyNoiseCurveWidget.axaml.cs index a0c6d06..3b1dead 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyNoiseCurveWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyNoiseCurveWidget.axaml.cs @@ -53,7 +53,7 @@ public partial class StudyNoiseCurveWidget : UserControl, IDesktopComponentWidge private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudyNoiseDistributionWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyNoiseDistributionWidget.axaml.cs index 6d94385..9e661dc 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyNoiseDistributionWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyNoiseDistributionWidget.axaml.cs @@ -40,7 +40,7 @@ public partial class StudyNoiseDistributionWidget : UserControl, IDesktopCompone private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudyScoreOverviewWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudyScoreOverviewWidget.axaml.cs index 76d1b75..a5904b5 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudyScoreOverviewWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudyScoreOverviewWidget.axaml.cs @@ -40,7 +40,7 @@ public partial class StudyScoreOverviewWidget : UserControl, IDesktopComponentWi private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/StudySessionControlWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudySessionControlWidget.axaml.cs index 3826692..91c68fe 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudySessionControlWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudySessionControlWidget.axaml.cs @@ -50,7 +50,7 @@ public partial class StudySessionControlWidget : UserControl, IDesktopComponentW private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); private readonly StudyAnalyticsMonitoringLeaseCoordinator _monitoringLeaseCoordinator = StudyAnalyticsMonitoringLeaseCoordinatorFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; private readonly DispatcherTimer _uiTimer = new() diff --git a/desktop/LanMountainDesktop/Views/Components/StudySessionHistoryWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/StudySessionHistoryWidget.axaml.cs index e79bef2..44c93da 100644 --- a/desktop/LanMountainDesktop/Views/Components/StudySessionHistoryWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/StudySessionHistoryWidget.axaml.cs @@ -46,7 +46,7 @@ public partial class StudySessionHistoryWidget : UserControl, IDesktopComponentW private static readonly Color LightSubstrate = Color.Parse("#FFF1F5FA"); private readonly IStudyAnalyticsService _studyAnalyticsService = StudyAnalyticsServiceFactory.CreateDefault(); - private LanMountainDesktop.PluginSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _settingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private readonly LocalizationService _localizationService = new(); private readonly StudySnapshotRenderGate _renderGate; diff --git a/desktop/LanMountainDesktop/Views/Components/WeatherWidgetBase.cs b/desktop/LanMountainDesktop/Views/Components/WeatherWidgetBase.cs index 37d3349..241e3e7 100644 --- a/desktop/LanMountainDesktop/Views/Components/WeatherWidgetBase.cs +++ b/desktop/LanMountainDesktop/Views/Components/WeatherWidgetBase.cs @@ -8,9 +8,9 @@ using Avalonia.Controls; using Avalonia.Media; using Avalonia.Threading; using LanMountainDesktop.ComponentSystem; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; @@ -31,7 +31,7 @@ public abstract class WeatherWidgetBase : UserControl, IWeatherInfoAwareComponentWidget, IComponentRuntimeContextAware, IComponentPlacementContextAware, - IComponentChromeContextAware + IAirAppComponentChromeContextAware { private readonly DispatcherTimer _refreshTimer = new(); private CancellationTokenSource? _refreshCancellation; @@ -110,7 +110,7 @@ public abstract class WeatherWidgetBase : UserControl, ConfigureRefreshTimer(); } - public virtual void SetComponentChromeContext(ComponentChromeContext context) + public virtual void SetAirAppComponentChromeContext(AirAppComponentChromeContext context) { ApplyCellSize(context.CellSize); } @@ -352,7 +352,7 @@ public abstract class WeatherWidgetBase : UserControl, private void OnSettingsChanged(object? sender, SettingsChangedEvent e) { - if (e.Scope != SettingsScope.App) + if (e.Scope != AirAppSettingsScope.App) { return; } @@ -377,7 +377,7 @@ public abstract class WeatherWidgetBase : UserControl, } var snapshot = _settingsService.LoadSnapshot( - SettingsScope.ComponentInstance, + AirAppSettingsScope.ComponentInstance, _componentId, _placementId); diff --git a/desktop/LanMountainDesktop/Views/Components/WorldClockWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/WorldClockWidget.axaml.cs index 4b3aa53..d821c87 100644 --- a/desktop/LanMountainDesktop/Views/Components/WorldClockWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/WorldClockWidget.axaml.cs @@ -97,7 +97,7 @@ public partial class WorldClockWidget : UserControl, Interval = TimeSpan.FromSeconds(1) }; - private LanMountainDesktop.PluginSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; + private LanMountainDesktop.AirAppSdk.ISettingsService _appSettingsService = LanMountainDesktop.Services.Settings.HostSettingsFacadeProvider.GetOrCreate().Settings; private IComponentInstanceSettingsStore _componentSettingsStore = HostComponentSettingsStoreProvider.GetOrCreate(); private readonly LocalizationService _localizationService = new(); private readonly ClockEntryVisual[] _entryVisuals = new ClockEntryVisual[WorldClockTimeZoneCatalog.ClockCount]; diff --git a/desktop/LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml.cs b/desktop/LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml.cs index a50cdcd..756253f 100644 --- a/desktop/LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml.cs +++ b/desktop/LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml.cs @@ -16,7 +16,7 @@ using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Views.Components; diff --git a/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs b/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs index 03e0b31..7645c9a 100644 --- a/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs +++ b/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs @@ -89,7 +89,7 @@ public partial class FusedDesktopComponentLibraryControl : UserControl private void LoadRegistry() { - var pluginRuntimeService = (Application.Current as App)?.PluginRuntimeService; + var pluginRuntimeService = (Application.Current as App)?.AirAppRuntimeService; _componentRegistry = DesktopComponentRegistryFactory.Create(pluginRuntimeService); _componentRuntimeRegistry = DesktopComponentRegistryFactory.CreateRuntimeRegistry( _componentRegistry, diff --git a/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs b/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs index 99c5645..cb8526e 100644 --- a/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs +++ b/desktop/LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs @@ -4,11 +4,11 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Interactivity; -using LanMountainDesktop.Appearance; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Platform.Windows; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; namespace LanMountainDesktop.Views; diff --git a/desktop/LanMountainDesktop/Views/MainWindow.ComponentSystem.cs b/desktop/LanMountainDesktop/Views/MainWindow.ComponentSystem.cs index 286bfc4..acf38d7 100644 --- a/desktop/LanMountainDesktop/Views/MainWindow.ComponentSystem.cs +++ b/desktop/LanMountainDesktop/Views/MainWindow.ComponentSystem.cs @@ -16,11 +16,11 @@ using FluentIcons.Avalonia; using FluentIcons.Common; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.DesktopEditing; -using LanMountainDesktop.Host.Abstractions; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.Abstractions; using LanMountainDesktop.Services; -using LanMountainDesktop.Settings.Core; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Theme; using LanMountainDesktop.Views.Components; using PathShape = Avalonia.Controls.Shapes.Path; @@ -2481,7 +2481,7 @@ public partial class MainWindow : Window if (_componentRuntimeRegistry.TryGetDescriptor(componentId, out var runtimeDescriptor)) { - return runtimeDescriptor.ResolveCornerRadius(new ComponentChromeContext( + return runtimeDescriptor.ResolveCornerRadius(new AirAppComponentChromeContext( componentId, null, _currentDesktopCellSize, diff --git a/desktop/LanMountainDesktop/Views/MainWindow.DesktopPaging.cs b/desktop/LanMountainDesktop/Views/MainWindow.DesktopPaging.cs index 7b515f2..e370287 100644 --- a/desktop/LanMountainDesktop/Views/MainWindow.DesktopPaging.cs +++ b/desktop/LanMountainDesktop/Views/MainWindow.DesktopPaging.cs @@ -17,7 +17,7 @@ using Avalonia.VisualTree; using FluentAvalonia.UI.Controls; using LanMountainDesktop.Models; using LanMountainDesktop.Platform.Windows; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Theme; @@ -496,7 +496,7 @@ public partial class MainWindow : Window return; } - var appSnapshot = _settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var appSnapshot = _settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); var isThreeFingerSwipeEnabled = appSnapshot.EnableThreeFingerSwipe; var currentPoint = e.GetCurrentPoint(DesktopPagesViewport); diff --git a/desktop/LanMountainDesktop/Views/MainWindow.SettingsHardCut.Stubs.cs b/desktop/LanMountainDesktop/Views/MainWindow.SettingsHardCut.Stubs.cs index 661752c..a44f1dd 100644 --- a/desktop/LanMountainDesktop/Views/MainWindow.SettingsHardCut.Stubs.cs +++ b/desktop/LanMountainDesktop/Views/MainWindow.SettingsHardCut.Stubs.cs @@ -13,7 +13,7 @@ using Avalonia.Styling; using Avalonia.Threading; using FluentAvalonia.UI.Controls; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Update; using LanMountainDesktop.Theme; @@ -39,13 +39,13 @@ public partial class MainWindow : Window return; } - // 缁勪欢瀹炰緥鑼冨洿鐨勮缃彉鏇翠笉搴旇Е鍙戞暣涓闈㈤噸鏂板姞杞斤紙姣斿缈婚〉淇濆瓨鍥剧墖绱㈠紩锛? if (e.Scope == SettingsScope.ComponentInstance) + // 缁勪欢瀹炰緥鑼冨洿鐨勮缃彉鏇翠笉搴旇Е鍙戞暣涓闈㈤噸鏂板姞杞斤紙姣斿缈婚〉淇濆瓨鍥剧墖绱㈠紩锛? if (e.Scope == AirAppSettingsScope.ComponentInstance) { return; } // 鍚姩鍙拌缃彉鍖栨椂锛岄噸鏂版覆鏌撳惎鍔ㄥ彴鍥炬爣 - if (e.Scope == SettingsScope.Launcher && e.ChangedKeys is { Count: > 0 }) + if (e.Scope == AirAppSettingsScope.Launcher && e.ChangedKeys is { Count: > 0 }) { var changedKeys = e.ChangedKeys.ToArray(); if (changedKeys.Any(key => @@ -53,7 +53,7 @@ public partial class MainWindow : Window { Dispatcher.UIThread.Post(() => { - var launcherSnapshot = _settingsService.LoadSnapshot(SettingsScope.Launcher); + var launcherSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.Launcher); InitializeLauncherVisibilitySettings(launcherSnapshot); RenderLauncherRootTiles(); }, DispatcherPriority.Background); @@ -61,7 +61,7 @@ public partial class MainWindow : Window } } - if (e.Scope == SettingsScope.App && e.ChangedKeys is { Count: > 0 }) + if (e.Scope == AirAppSettingsScope.App && e.ChangedKeys is { Count: > 0 }) { var changedKeys = e.ChangedKeys.ToArray(); if (changedKeys.Any(key => @@ -72,7 +72,7 @@ public partial class MainWindow : Window { Dispatcher.UIThread.Post(() => { - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); _backToWindowsButtonDisplayMode = NormalizeBackToWindowsButtonDisplayMode(snapshot.BackToWindowsButtonDisplayMode); _backToWindowsIconSource = NormalizeBackToWindowsIconSource(snapshot.BackToWindowsIconSource); _backToWindowsFluentIconName = NormalizeBackToWindowsFluentIcon(snapshot.BackToWindowsFluentIconName).ToString(); @@ -533,9 +533,9 @@ public partial class MainWindow : Window { // Saving our own state should not trigger a full external reload cycle. _suppressOwnSettingsReloadCount++; - _settingsService.SaveSnapshot(SettingsScope.App, BuildAppSettingsSnapshot()); + _settingsService.SaveSnapshot(AirAppSettingsScope.App, BuildAppSettingsSnapshot()); _componentLayoutStore.SaveLayout(BuildDesktopLayoutSettingsSnapshot()); - _settingsService.SaveSnapshot(SettingsScope.Launcher, BuildLauncherSettingsSnapshot()); + _settingsService.SaveSnapshot(AirAppSettingsScope.Launcher, BuildLauncherSettingsSnapshot()); } catch (Exception ex) { @@ -568,9 +568,9 @@ public partial class MainWindow : Window internal void ReloadFromPersistedSettings() { - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var layoutSnapshot = _componentLayoutStore.LoadLayout(); - var launcherSnapshot = _settingsService.LoadSnapshot(SettingsScope.Launcher); + var launcherSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.Launcher); _suppressSettingsPersistence = true; try { @@ -637,7 +637,7 @@ public partial class MainWindow : Window var latestUpdateState = _updateSettingsService.Get(); var latestThemeState = _themeSettingsService.Get(); var latestPrivacyState = _settingsFacade.Privacy.Get(); - var existingSnapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var existingSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); return new AppSettingsSnapshot { GridShortSideCells = _targetShortSideCells, diff --git a/desktop/LanMountainDesktop/Views/MainWindow.axaml.cs b/desktop/LanMountainDesktop/Views/MainWindow.axaml.cs index ecfcb03..d3518d7 100644 --- a/desktop/LanMountainDesktop/Views/MainWindow.axaml.cs +++ b/desktop/LanMountainDesktop/Views/MainWindow.axaml.cs @@ -23,7 +23,7 @@ using FluentIcons.Avalonia; using FluentAvalonia.Styling; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.Shared.Contracts.Launcher; @@ -203,7 +203,7 @@ public partial class MainWindow : Window { var pluginRuntimeService = Design.IsDesignMode ? null - : (Application.Current as App)?.PluginRuntimeService; + : (Application.Current as App)?.AirAppRuntimeService; _componentRegistry = DesktopComponentRegistryFactory.Create(pluginRuntimeService); _settingsService = _settingsFacade.Settings; _gridSettingsService = _settingsFacade.Grid; @@ -456,9 +456,9 @@ public partial class MainWindow : Window SyncSettingsWindowState(); _suppressSettingsPersistence = true; - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); var desktopLayoutSnapshot = _componentLayoutStore.LoadLayout(); - var launcherSnapshot = _settingsService.LoadSnapshot(SettingsScope.Launcher); + var launcherSnapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.Launcher); if (!string.IsNullOrWhiteSpace(snapshot.TimeZoneId)) { @@ -1080,7 +1080,7 @@ public partial class MainWindow : Window return; } - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); if (snapshot.ShowInTaskbar) { WindowState = WindowState.Minimized; @@ -1167,7 +1167,7 @@ public partial class MainWindow : Window private StartupVisualPreferences GetStartupVisualPreferences() { - var snapshot = _settingsService.LoadSnapshot(SettingsScope.App); + var snapshot = _settingsService.LoadSnapshot(AirAppSettingsScope.App); return StartupVisualPreferencesResolver.FromFlags( snapshot.EnableFadeTransition, snapshot.EnableSlideTransition); diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml.cs b/desktop/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml.cs index 40fd3cd..3955405 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml.cs +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml.cs @@ -6,7 +6,7 @@ using Avalonia.Input; using Avalonia.VisualTree; using FluentAvalonia.UI.Controls; using LanMountainDesktop.Models; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.ViewModels; @@ -14,16 +14,16 @@ using LanMountainDesktop.Views; namespace LanMountainDesktop.Views.SettingsPages; -[SettingsPageInfo( +[AirAppSettingsPageInfo( "about", "About", - SettingsPageCategory.About, + AirAppSettingsPageCategory.About, IconKey = "Info", SortOrder = 40, TitleLocalizationKey = "settings.about.title", DescriptionLocalizationKey = "settings.about.description", HidePageTitle = true)] -public partial class AboutSettingsPage : SettingsPageBase +public partial class AboutSettingsPage : AirAppSettingsPageBase { private const double HeroAspectRatio = 9d / 16d; private const int DevModeActivationClicks = 5; @@ -92,7 +92,7 @@ public partial class AboutSettingsPage : SettingsPageBase _lastHeroCardClickTime = now; var settingsFacade = HostSettingsFacadeProvider.GetOrCreate(); - var snapshot = settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); if (snapshot.IsDevModeEnabled) { @@ -135,10 +135,10 @@ public partial class AboutSettingsPage : SettingsPageBase return; } - var snapshot = settingsFacade.Settings.LoadSnapshot(SettingsScope.App); + var snapshot = settingsFacade.Settings.LoadSnapshot(AirAppSettingsScope.App); snapshot.IsDevModeEnabled = true; settingsFacade.Settings.SaveSnapshot( - SettingsScope.App, + AirAppSettingsScope.App, snapshot, changedKeys: [nameof(AppSettingsSnapshot.IsDevModeEnabled)]); diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml similarity index 97% rename from desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml index a7a6404..5e15c47 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml @@ -4,8 +4,8 @@ xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia" xmlns:helpers="using:LanMountainDesktop.Helpers" xmlns:fi="using:FluentIcons.Avalonia" - x:Class="LanMountainDesktop.Views.SettingsPages.PluginCatalogDetailDrawer" - x:DataType="vm:PluginCatalogDetailViewModel"> + x:Class="LanMountainDesktop.Views.SettingsPages.AirAppCatalogDetailDrawer" + x:DataType="vm:AirAppCatalogDetailViewModel"> @@ -103,7 +103,7 @@ TextWrapping="Wrap" /> + Engine="{x:Static helpers:AirAppCatalogMarkdownHelper.Engine}" /> diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml.cs b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml.cs similarity index 60% rename from desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml.cs rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml.cs index e7cf21f..3f9ade0 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogDetailDrawer.axaml.cs +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogDetailDrawer.axaml.cs @@ -3,14 +3,14 @@ using LanMountainDesktop.ViewModels; namespace LanMountainDesktop.Views.SettingsPages; -public partial class PluginCatalogDetailDrawer : UserControl +public partial class AirAppCatalogDetailDrawer : UserControl { - public PluginCatalogDetailDrawer() + public AirAppCatalogDetailDrawer() { InitializeComponent(); } - public PluginCatalogDetailDrawer(PluginCatalogDetailViewModel viewModel) + public AirAppCatalogDetailDrawer(AirAppCatalogDetailViewModel viewModel) { DataContext = viewModel; InitializeComponent(); diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml similarity index 95% rename from desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml index 7087971..d64cdcc 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml @@ -3,9 +3,9 @@ xmlns:vm="using:LanMountainDesktop.ViewModels" xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:fi="using:FluentIcons.Avalonia" - x:Class="LanMountainDesktop.Views.SettingsPages.PluginCatalogSettingsPage" + x:Class="LanMountainDesktop.Views.SettingsPages.AirAppCatalogSettingsPage" x:Name="Root" - x:DataType="vm:PluginCatalogSettingsPageViewModel"> + x:DataType="vm:AirAppCatalogSettingsPageViewModel"> - @@ -47,7 +47,7 @@ - + diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml.cs b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml.cs similarity index 79% rename from desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml.cs rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml.cs index 519aa98..cdf0483 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/PluginCatalogSettingsPage.axaml.cs +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppCatalogSettingsPage.axaml.cs @@ -1,29 +1,29 @@ using System; using Avalonia.Controls; -using LanMountainDesktop.PluginSdk; +using LanMountainDesktop.AirAppSdk; using LanMountainDesktop.Services; -using LanMountainDesktop.Services.PluginMarket; +using LanMountainDesktop.Services.AirAppMarket; using LanMountainDesktop.Services.Settings; using LanMountainDesktop.ViewModels; namespace LanMountainDesktop.Views.SettingsPages; -[SettingsPageInfo( +[AirAppSettingsPageInfo( "plugin-catalog", - "Plugin Catalog", - SettingsPageCategory.PluginCatalog, + "AirApp Catalog", + AirAppSettingsPageCategory.AirAppCatalog, IconKey = "ShoppingBag", SortOrder = 35, TitleLocalizationKey = "settings.plugin_catalog.title", DescriptionLocalizationKey = "settings.plugin_catalog.subtitle")] -public partial class PluginCatalogSettingsPage : SettingsPageBase +public partial class AirAppCatalogSettingsPage : AirAppSettingsPageBase { - public PluginCatalogSettingsPage() + public AirAppCatalogSettingsPage() : this(Design.IsDesignMode ? CreateDesignTimeViewModel() : CreateDefaultViewModel()) { } - public PluginCatalogSettingsPage(PluginCatalogSettingsPageViewModel viewModel) + public AirAppCatalogSettingsPage(AirAppCatalogSettingsPageViewModel viewModel) { ViewModel = viewModel; ViewModel.RestartRequested += OnRestartRequested; @@ -32,7 +32,7 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase InitializeComponent(); } - public PluginCatalogSettingsPageViewModel ViewModel { get; } + public AirAppCatalogSettingsPageViewModel ViewModel { get; } public override async void OnNavigatedTo(object? parameter) { @@ -55,24 +55,24 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase } } - private static PluginCatalogSettingsPageViewModel CreateDefaultViewModel() + private static AirAppCatalogSettingsPageViewModel CreateDefaultViewModel() { var settingsFacade = HostSettingsFacadeProvider.GetOrCreate(); var localizationService = new LocalizationService(); - var assetCache = new PluginMarketAssetCacheService(AppDataPathProvider.GetPluginMarketDirectory()); - return new PluginCatalogSettingsPageViewModel( + var assetCache = new AirAppMarketAssetCacheService(AppDataPathProvider.GetAirAppMarketDirectory()); + return new AirAppCatalogSettingsPageViewModel( settingsFacade, localizationService, new AirAppMarketIconService(assetCache), new AirAppMarketReadmeService(assetCache)); } - private static PluginCatalogSettingsPageViewModel CreateDesignTimeViewModel() + private static AirAppCatalogSettingsPageViewModel CreateDesignTimeViewModel() { var settingsFacade = HostSettingsFacadeProvider.GetOrCreate(); var localizationService = new LocalizationService(); - var assetCache = new PluginMarketAssetCacheService(AppDataPathProvider.GetPluginMarketDirectory()); - var viewModel = new PluginCatalogSettingsPageViewModel( + var assetCache = new AirAppMarketAssetCacheService(AppDataPathProvider.GetAirAppMarketDirectory()); + var viewModel = new AirAppCatalogSettingsPageViewModel( settingsFacade, localizationService, new AirAppMarketIconService(assetCache), @@ -102,7 +102,7 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase DateTimeOffset.Now.AddDays(-8), DateTimeOffset.Now.AddDays(-2)), localizationService, - installedPlugin: null, + installedAirApp: null, previewHostVersion), CreateCatalogItemViewModel( CreateCatalogItem( @@ -125,8 +125,8 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase DateTimeOffset.Now.AddDays(-30), DateTimeOffset.Now.AddDays(-1)), localizationService, - new InstalledPluginInfo( - new PluginManifest( + new AirAppInstalledInfo( + new AirAppManifest( "workspace-pulse", "Workspace Pulse", "WorkspacePulse.dll", @@ -159,14 +159,14 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase DateTimeOffset.Now.AddDays(-12), DateTimeOffset.Now.AddDays(-3)), localizationService, - installedPlugin: null, + installedAirApp: null, previewHostVersion) }; foreach (var item in items) { - viewModel.CatalogPlugins.Add(item); - viewModel.FilteredPlugins.Add(item); + viewModel.CatalogAirApps.Add(item); + viewModel.FilteredAirApps.Add(item); } viewModel.ShowEmptyState = false; @@ -180,28 +180,28 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase RequestRestart(reason ?? ViewModel.RestartRequiredMessage); } - private async void OnDetailsRequested(PluginCatalogItemViewModel item) + private async void OnDetailsRequested(AirAppCatalogItemViewModel item) { var detailViewModel = ViewModel.CreateDetailViewModel(item); - var drawer = new PluginCatalogDetailDrawer(detailViewModel); + var drawer = new AirAppCatalogDetailDrawer(detailViewModel); OpenDrawer(drawer, detailViewModel.DrawerTitle); await detailViewModel.InitializeAsync(); } - private static PluginCatalogItemViewModel CreateCatalogItemViewModel( - PluginCatalogItemInfo plugin, + private static AirAppCatalogItemViewModel CreateCatalogItemViewModel( + AirAppCatalogItemInfo plugin, LocalizationService localizationService, - InstalledPluginInfo? installedPlugin, + AirAppInstalledInfo? installedAirApp, Version hostVersion) { var languageCode = localizationService.NormalizeLanguageCode( HostSettingsFacadeProvider.GetOrCreate().Region.Get().LanguageCode); - var item = new PluginCatalogItemViewModel(plugin, localizationService, languageCode); - item.ApplyInstallState(installedPlugin, hostVersion); + var item = new AirAppCatalogItemViewModel(plugin, localizationService, languageCode); + item.ApplyInstallState(installedAirApp, hostVersion); return item; } - private static PluginCatalogItemInfo CreateCatalogItem( + private static AirAppCatalogItemInfo CreateCatalogItem( string id, string name, string description, @@ -217,12 +217,12 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase string homepageUrl, string repositoryUrl, string[] tags, - PluginCatalogSharedContractInfo[] sharedContracts, + AirAppCatalogSharedContractInfo[] sharedContracts, DateTimeOffset publishedAt, DateTimeOffset updatedAt) { - return new PluginCatalogItemInfo( - new PluginCatalogManifestInfo( + return new AirAppCatalogItemInfo( + new AirAppCatalogManifestInfo( id, name, description, @@ -231,10 +231,10 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase apiVersion, string.Empty, sharedContracts), - new PluginCatalogCompatibilityInfo( + new AirAppCatalogCompatibilityInfo( minHostVersion, apiVersion), - new PluginCatalogRepositoryInfo( + new AirAppCatalogRepositoryInfo( iconUrl, homepageUrl, readmeUrl, @@ -242,7 +242,7 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase repositoryUrl, tags, string.Empty), - new PluginCatalogPublicationInfo( + new AirAppCatalogPublicationInfo( releaseTag, releaseAssetName, publishedAt, @@ -253,10 +253,10 @@ public partial class PluginCatalogSettingsPage : SettingsPageBase string.IsNullOrWhiteSpace(downloadUrl) ? [] : [ - new PluginPackageSourceInfo( + new AirAppPackageSourceInfo( string.IsNullOrWhiteSpace(releaseTag) - ? LanMountainDesktop.Services.Settings.PluginPackageSourceKind.RawFallback - : LanMountainDesktop.Services.Settings.PluginPackageSourceKind.ReleaseAsset, + ? LanMountainDesktop.Services.Settings.AirAppPackageSourceKind.RawFallback + : LanMountainDesktop.Services.Settings.AirAppPackageSourceKind.ReleaseAsset, downloadUrl, string.Empty, 0) diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/GeneratedPluginSettingsPage.axaml b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppGeneratedSettingsPage.axaml similarity index 89% rename from desktop/LanMountainDesktop/Views/SettingsPages/GeneratedPluginSettingsPage.axaml rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppGeneratedSettingsPage.axaml index 1cfcc5b..c90390d 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/GeneratedPluginSettingsPage.axaml +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppGeneratedSettingsPage.axaml @@ -1,8 +1,8 @@ + x:Class="LanMountainDesktop.Views.SettingsPages.GeneratedAirAppSettingsPage" + x:DataType="vm:AirAppGeneratedSettingsPageViewModel"> ( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id) ?? (option.DefaultValue as bool? ?? false) }; toggleSwitch.IsCheckedChanged += (_, _) => { ViewModel.SettingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, toggleSwitch.IsChecked == true, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id, changedKeys: [option.Key]); }; @@ -108,12 +108,12 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase return toggleSwitch; } - private Control CreateNumber(SettingsOptionDefinition option) + private Control CreateNumber(AirAppSettingOptionDefinition option) { var currentValue = ViewModel.SettingsService.GetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id); var numeric = new NumericUpDown @@ -126,10 +126,10 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase numeric.ValueChanged += (_, _) => { ViewModel.SettingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, (double)(numeric.Value ?? 0m), - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id, changedKeys: [option.Key]); }; @@ -137,7 +137,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase return numeric; } - private Control CreateSelect(SettingsOptionDefinition option) + private Control CreateSelect(AirAppSettingOptionDefinition option) { var choices = option.Choices .Select(choice => new SelectionOption( @@ -151,9 +151,9 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase }; var currentValue = ViewModel.SettingsService.GetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id); comboBox.SelectedItem = choices.FirstOrDefault(choice => string.Equals(choice.Value, currentValue ?? option.DefaultValue?.ToString(), StringComparison.OrdinalIgnoreCase)); @@ -166,10 +166,10 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } ViewModel.SettingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, selected.Value, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id, changedKeys: [option.Key]); }; @@ -177,20 +177,20 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase return comboBox; } - private Control CreateText(SettingsOptionDefinition option, string? watermark) + private Control CreateText(AirAppSettingOptionDefinition option, string? watermark) { - var currentValue = option.OptionType == SettingsOptionType.List + var currentValue = option.OptionType == AirAppSettingOptionType.List ? string.Join( ", ", ViewModel.SettingsService.GetValue>( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id) ?? (option.DefaultValue as IReadOnlyList ?? [])) : ViewModel.SettingsService.GetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id) ?? option.DefaultValue?.ToString() ?? string.Empty; var textBox = new TextBox @@ -201,17 +201,17 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase textBox.LostFocus += (_, _) => { - object value = option.OptionType == SettingsOptionType.List + object value = option.OptionType == AirAppSettingOptionType.List ? textBox.Text? .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .ToArray() ?? [] : textBox.Text ?? string.Empty; ViewModel.SettingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, option.Key, value, - ViewModel.PluginId, + ViewModel.AirAppId, sectionId: ViewModel.Section.Id, changedKeys: [option.Key]); }; @@ -219,57 +219,57 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase return textBox; } - private static PluginGeneratedSettingsPageViewModel CreateDefaultViewModel() + private static AirAppGeneratedSettingsPageViewModel CreateDefaultViewModel() { - return new PluginGeneratedSettingsPageViewModel( + return new AirAppGeneratedSettingsPageViewModel( HostSettingsFacadeProvider.GetOrCreate().Settings, string.Empty, - new PluginSettingsSectionRegistration("_preview", "preview", []), - new PluginLocalizer(AppContext.BaseDirectory, "en-US")); + new AirAppSettingsSectionRegistration("_preview", "preview", []), + new AirAppLocalizer(AppContext.BaseDirectory, "en-US")); } - private static PluginGeneratedSettingsPageViewModel CreateDesignTimeViewModel() + private static AirAppGeneratedSettingsPageViewModel CreateDesignTimeViewModel() { const string pluginId = "preview.plugin"; var settingsService = new DesignTimeSettingsService(); - var section = new PluginSettingsSectionRegistration( + var section = new AirAppSettingsSectionRegistration( "desktop_preview", "Preview Widget Settings", [ - new SettingsOptionDefinition( + new AirAppSettingOptionDefinition( "enable_glow", - SettingsOptionType.Toggle, + AirAppSettingOptionType.Toggle, "Enable glow", "Adds a soft highlight around the preview widget.", true), - new SettingsOptionDefinition( + new AirAppSettingOptionDefinition( "refresh_minutes", - SettingsOptionType.Number, + AirAppSettingOptionType.Number, "Refresh interval", "How often the plugin refreshes its cached content.", 30d, minimum: 5d, maximum: 120d), - new SettingsOptionDefinition( + new AirAppSettingOptionDefinition( "layout_density", - SettingsOptionType.Select, + AirAppSettingOptionType.Select, "Layout density", "Choose how compact the widget layout should feel.", "balanced", [ - new SettingsOptionChoice("compact", "Compact"), - new SettingsOptionChoice("balanced", "Balanced"), - new SettingsOptionChoice("comfortable", "Comfortable") + new AirAppSettingOptionChoice("compact", "Compact"), + new AirAppSettingOptionChoice("balanced", "Balanced"), + new AirAppSettingOptionChoice("comfortable", "Comfortable") ]), - new SettingsOptionDefinition( + new AirAppSettingOptionDefinition( "content_path", - SettingsOptionType.Path, + AirAppSettingOptionType.Path, "Content folder", "Local folder used by the plugin for mock assets.", - @"C:\Preview\PluginAssets"), - new SettingsOptionDefinition( + @"C:\Preview\AirAppAssets"), + new AirAppSettingOptionDefinition( "keywords", - SettingsOptionType.List, + AirAppSettingOptionType.List, "Pinned keywords", "Comma-separated topics that will be emphasized in the widget.", new[] { "avalonia", "preview", "design-time" }) @@ -277,41 +277,41 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase "Mock plugin settings shown only in Avalonia design mode."); settingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, "enable_glow", true, pluginId, sectionId: section.Id); settingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, "refresh_minutes", 30d, pluginId, sectionId: section.Id); settingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, "layout_density", "balanced", pluginId, sectionId: section.Id); settingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, "content_path", - @"C:\Preview\PluginAssets", + @"C:\Preview\AirAppAssets", pluginId, sectionId: section.Id); settingsService.SetValue( - SettingsScope.Plugin, + AirAppSettingsScope.AirApp, "keywords", new[] { "avalonia", "preview", "design-time" }, pluginId, sectionId: section.Id); - return new PluginGeneratedSettingsPageViewModel( + return new AirAppGeneratedSettingsPageViewModel( settingsService, pluginId, section, - new PluginLocalizer(AppContext.BaseDirectory, "en-US")); + new AirAppLocalizer(AppContext.BaseDirectory, "en-US")); } private sealed class DesignTimeSettingsService : ISettingsService @@ -320,11 +320,11 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase public event EventHandler? Changed; - public T LoadSnapshot(SettingsScope scope, string? subjectId = null, string? placementId = null) where T : new() + public T LoadSnapshot(AirAppSettingsScope scope, string? subjectId = null, string? placementId = null) where T : new() => new(); public void SaveSnapshot( - SettingsScope scope, + AirAppSettingsScope scope, T snapshot, string? subjectId = null, string? placementId = null, @@ -335,14 +335,14 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } public T LoadSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null) where T : new() => new(); public void SaveSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, T section, @@ -353,7 +353,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } public void DeleteSection( - SettingsScope scope, + AirAppSettingsScope scope, string subjectId, string sectionId, string? placementId = null) @@ -368,7 +368,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } public T? GetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, string? subjectId = null, string? placementId = null, @@ -380,7 +380,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } public void SetValue( - SettingsScope scope, + AirAppSettingsScope scope, string key, T value, string? subjectId = null, @@ -421,7 +421,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } private static string BuildStorageKey( - SettingsScope scope, + AirAppSettingsScope scope, string? subjectId, string? placementId, string? sectionId, @@ -437,7 +437,7 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase } private void RaiseChanged( - SettingsScope scope, + AirAppSettingsScope scope, string? subjectId, string? placementId, string? sectionId, @@ -466,24 +466,24 @@ public partial class GeneratedPluginSettingsPage : SettingsPageBase public string? PlacementId { get; } public T LoadSnapshot() where T : new() - => _settingsService.LoadSnapshot(SettingsScope.ComponentInstance, ComponentId, PlacementId); + => _settingsService.LoadSnapshot(AirAppSettingsScope.ComponentInstance, ComponentId, PlacementId); public void SaveSnapshot(T snapshot, IReadOnlyCollection? changedKeys = null) - => _settingsService.SaveSnapshot(SettingsScope.ComponentInstance, snapshot, ComponentId, PlacementId, changedKeys: changedKeys); + => _settingsService.SaveSnapshot(AirAppSettingsScope.ComponentInstance, snapshot, ComponentId, PlacementId, changedKeys: changedKeys); public T LoadSection(string sectionId) where T : new() - => _settingsService.LoadSection(SettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); + => _settingsService.LoadSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); public void SaveSection(string sectionId, T section, IReadOnlyCollection? changedKeys = null) - => _settingsService.SaveSection(SettingsScope.ComponentInstance, ComponentId, sectionId, section, PlacementId, changedKeys); + => _settingsService.SaveSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, section, PlacementId, changedKeys); public void DeleteSection(string sectionId) - => _settingsService.DeleteSection(SettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); + => _settingsService.DeleteSection(AirAppSettingsScope.ComponentInstance, ComponentId, sectionId, PlacementId); public T? GetValue(string key) - => _settingsService.GetValue(SettingsScope.ComponentInstance, key, ComponentId, PlacementId); + => _settingsService.GetValue(AirAppSettingsScope.ComponentInstance, key, ComponentId, PlacementId); public void SetValue(string key, T value, IReadOnlyCollection? changedKeys = null) - => _settingsService.SetValue(SettingsScope.ComponentInstance, key, value, ComponentId, PlacementId, changedKeys: changedKeys); + => _settingsService.SetValue(AirAppSettingsScope.ComponentInstance, key, value, ComponentId, PlacementId, changedKeys: changedKeys); } } diff --git a/desktop/LanMountainDesktop/Views/SettingsPages/PluginsSettingsPage.axaml b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppsSettingsPage.axaml similarity index 89% rename from desktop/LanMountainDesktop/Views/SettingsPages/PluginsSettingsPage.axaml rename to desktop/LanMountainDesktop/Views/SettingsPages/AirAppsSettingsPage.axaml index fb00209..d7a5039 100644 --- a/desktop/LanMountainDesktop/Views/SettingsPages/PluginsSettingsPage.axaml +++ b/desktop/LanMountainDesktop/Views/SettingsPages/AirAppsSettingsPage.axaml @@ -4,9 +4,9 @@ xmlns:controls="using:LanMountainDesktop.Controls" xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:fi="using:FluentIcons.Avalonia" - x:Class="LanMountainDesktop.Views.SettingsPages.PluginsSettingsPage" + x:Class="LanMountainDesktop.Views.SettingsPages.AirAppsSettingsPage" x:Name="Root" - x:DataType="vm:PluginsSettingsPageViewModel"> + x:DataType="vm:AirAppsSettingsPageViewModel"> - + - + @@ -42,9 +42,9 @@ -