diff --git a/Directory.Packages.props b/Directory.Packages.props
index f74d74b..b5802d1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -47,6 +47,7 @@
+
diff --git a/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs b/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs
index 7094b9d..d88f0d0 100644
--- a/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs
+++ b/LanMountainDesktop.AirAppHost/AirAppLaunchOptions.cs
@@ -7,10 +7,12 @@ public sealed record AirAppLaunchOptions(
string? SourcePlacementId,
string? LauncherPipeName,
string? InstanceKey,
- string? DataRoot)
+ string? DataRoot,
+ string? TargetEntryId)
{
public const string WorldClockAppId = "world-clock";
public const string WhiteboardAppId = "whiteboard";
+ public const string RssReaderAppId = "rss-reader";
public static AirAppLaunchOptions Parse(IReadOnlyList args)
{
@@ -60,7 +62,8 @@ public sealed record AirAppLaunchOptions(
GetOptionalValue(values, "source-placement-id"),
GetOptionalValue(values, "launcher-pipe"),
GetOptionalValue(values, "instance-key"),
- GetOptionalValue(values, "data-root"));
+ GetOptionalValue(values, "data-root"),
+ GetOptionalValue(values, "target-entry-id"));
}
private static string GetValue(IReadOnlyDictionary values, string key, string fallback)
diff --git a/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs b/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs
index 6e3af58..1bc6744 100644
--- a/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs
+++ b/LanMountainDesktop.AirAppHost/AirAppWindow.axaml.cs
@@ -4,6 +4,7 @@ using Avalonia.Threading;
using FluentAvalonia.UI.Windowing;
using LanMountainDesktop.ComponentSystem;
using LanMountainDesktop.Services;
+using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.Shared.IPC;
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
using LanMountainDesktop.Views.Components;
@@ -25,11 +26,39 @@ public sealed partial class AirAppWindow : FAAppWindow
public AirAppWindow(AirAppLaunchOptions options)
{
_options = options;
- _descriptor = AirAppWindowDescriptor.Create(options);
+ _descriptor = LocalizeDescriptor(AirAppWindowDescriptor.Create(options), options);
InitializeComponent();
ConfigureWindow();
}
+ private static AirAppWindowDescriptor LocalizeDescriptor(
+ AirAppWindowDescriptor descriptor,
+ AirAppLaunchOptions options)
+ {
+ if (!string.Equals(options.AppId, AirAppLaunchOptions.RssReaderAppId, StringComparison.OrdinalIgnoreCase))
+ return descriptor;
+
+ var localization = new LocalizationService();
+ string languageCode;
+ try
+ {
+ languageCode = localization.NormalizeLanguageCode(new AppSettingsService().Load().LanguageCode);
+ }
+ catch
+ {
+ languageCode = "zh-CN";
+ }
+
+ var title = localization.GetString(languageCode, "component.rss_reader", "RSS Reader");
+ var airApp = localization.GetString(languageCode, "rss.air_app", "Air APP");
+ return descriptor with
+ {
+ WindowTitle = $"{title} - {airApp}",
+ TitleBarTitle = title,
+ TitleBarSubtitle = airApp
+ };
+ }
+
private void ConfigureWindow()
{
ApplyWindowDescriptor(_descriptor);
@@ -46,6 +75,12 @@ public sealed partial class AirAppWindow : FAAppWindow
return;
}
+ if (string.Equals(_options.AppId, AirAppLaunchOptions.RssReaderAppId, StringComparison.OrdinalIgnoreCase))
+ {
+ ContentHost.Content = new RssReaderAirAppView(_options);
+ return;
+ }
+
ContentHost.Content = new TextBlock
{
Text = $"Unsupported Air APP: {_options.AppId}",
@@ -263,6 +298,11 @@ public sealed partial class AirAppWindow : FAAppWindow
return $"{AirAppLaunchOptions.WorldClockAppId}:clock-suite:global";
}
+ if (string.Equals(_options.AppId, AirAppLaunchOptions.RssReaderAppId, StringComparison.OrdinalIgnoreCase))
+ {
+ return $"{AirAppLaunchOptions.RssReaderAppId}:global";
+ }
+
var componentId = string.IsNullOrWhiteSpace(_options.SourceComponentId)
? "none"
: _options.SourceComponentId.Trim();
diff --git a/LanMountainDesktop.AirAppHost/AirAppWindowDescriptor.cs b/LanMountainDesktop.AirAppHost/AirAppWindowDescriptor.cs
index 4a5111d..294ff11 100644
--- a/LanMountainDesktop.AirAppHost/AirAppWindowDescriptor.cs
+++ b/LanMountainDesktop.AirAppHost/AirAppWindowDescriptor.cs
@@ -43,6 +43,20 @@ public sealed record AirAppWindowDescriptor(
"Air APP");
}
+ if (string.Equals(options.AppId, AirAppLaunchOptions.RssReaderAppId, StringComparison.OrdinalIgnoreCase))
+ {
+ return Standard(
+ "RSS Reader - Air APP",
+ "RSS Reader",
+ "Air APP",
+ width: 1100,
+ height: 720,
+ minWidth: 760,
+ minHeight: 520,
+ canResize: true,
+ showAsDialog: false);
+ }
+
return Standard(
"Air APP",
"Air APP",
diff --git a/LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj b/LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj
index 14a2984..cbc1008 100644
--- a/LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj
+++ b/LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj
@@ -24,6 +24,7 @@
+
diff --git a/LanMountainDesktop.AirAppRuntime/AirAppInstanceKey.cs b/LanMountainDesktop.AirAppRuntime/AirAppInstanceKey.cs
index af49efd..fa972b0 100644
--- a/LanMountainDesktop.AirAppRuntime/AirAppInstanceKey.cs
+++ b/LanMountainDesktop.AirAppRuntime/AirAppInstanceKey.cs
@@ -10,6 +10,11 @@ internal static class AirAppInstanceKey
return $"{normalizedAppId}:clock-suite:global";
}
+ if (string.Equals(normalizedAppId, "rss-reader", StringComparison.OrdinalIgnoreCase))
+ {
+ return $"{normalizedAppId}:global";
+ }
+
var normalizedComponentId = Normalize(sourceComponentId, "none");
var normalizedPlacementId = Normalize(sourcePlacementId, "none");
return $"{normalizedAppId}:{normalizedComponentId}:{normalizedPlacementId}";
diff --git a/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs b/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs
index 97b75c5..625ba37 100644
--- a/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs
+++ b/LanMountainDesktop.AirAppRuntime/AirAppLifecycleService.cs
@@ -42,7 +42,8 @@ internal sealed class AirAppLifecycleService : IAirAppLifecycleService
sessionId,
instanceKey,
request.SourceComponentId,
- request.SourcePlacementId);
+ request.SourcePlacementId,
+ request.TargetEntryId);
if (process is null)
{
return Task.FromResult(BuildResult(false, "start_failed", "AirAppHost process was not created.", null));
diff --git a/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs b/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs
index 7414a8b..bf21af0 100644
--- a/LanMountainDesktop.AirAppRuntime/IAirAppProcessStarter.cs
+++ b/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);
+ Process? Start(string appId, string sessionId, string instanceKey, string? sourceComponentId, string? sourcePlacementId, string? targetEntryId = null);
}
internal sealed class AirAppProcessStarter : IAirAppProcessStarter
@@ -32,7 +32,8 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter
string sessionId,
string instanceKey,
string? sourceComponentId,
- string? sourcePlacementId)
+ string? sourcePlacementId,
+ string? targetEntryId = null)
{
var hostPath = _locator.Resolve(_packageRootProvider(), _hostPathProvider());
var startInfo = CreateStartInfo(hostPath);
@@ -57,6 +58,11 @@ internal sealed class AirAppProcessStarter : IAirAppProcessStarter
AddArgument(startInfo, "--source-placement-id", sourcePlacementId.Trim());
}
+ if (!string.IsNullOrWhiteSpace(targetEntryId))
+ {
+ AddArgument(startInfo, "--target-entry-id", targetEntryId.Trim());
+ }
+
AirAppRuntimeLogger.Info(
$"Starting AirAppHost. AppId='{appId}'; InstanceKey='{instanceKey}'; HostPath='{hostPath}'; DataRoot='{dataRoot ?? string.Empty}'.");
var process = Process.Start(startInfo);
diff --git a/LanMountainDesktop.Shared.IPC/Abstractions/Services/IAirAppLifecycleService.cs b/LanMountainDesktop.Shared.IPC/Abstractions/Services/IAirAppLifecycleService.cs
index 68c6474..cf192cd 100644
--- a/LanMountainDesktop.Shared.IPC/Abstractions/Services/IAirAppLifecycleService.cs
+++ b/LanMountainDesktop.Shared.IPC/Abstractions/Services/IAirAppLifecycleService.cs
@@ -22,7 +22,8 @@ public sealed record AirAppOpenRequest(
string AppId,
string? SourceComponentId,
string? SourcePlacementId,
- int RequesterProcessId);
+ int RequesterProcessId,
+ string? TargetEntryId = null);
public sealed record AirAppRegistrationRequest(
string InstanceKey,
diff --git a/LanMountainDesktop.Tests/AirAppLauncherServiceTests.cs b/LanMountainDesktop.Tests/AirAppLauncherServiceTests.cs
index 3cd3297..be1a653 100644
--- a/LanMountainDesktop.Tests/AirAppLauncherServiceTests.cs
+++ b/LanMountainDesktop.Tests/AirAppLauncherServiceTests.cs
@@ -95,6 +95,22 @@ public sealed class AirAppLauncherServiceTests
Assert.Equal(analogKey, worldKey);
}
+ [Fact]
+ public void RssReaderRequest_CarriesEntryAndUsesGlobalInstance()
+ {
+ var request = AirAppLauncherService.BuildOpenRequest(
+ AirAppLauncherService.RssReaderAppId,
+ BuiltInComponentIds.DesktopRssReader,
+ "rss-placement",
+ 88,
+ "entry-42");
+
+ Assert.Equal("rss-reader", request.AppId);
+ Assert.Equal("entry-42", request.TargetEntryId);
+ Assert.Equal("rss-reader:global", AirAppLauncherService.BuildSingleInstanceKey(
+ request.AppId, request.SourceComponentId, request.SourcePlacementId));
+ }
+
[Fact]
public void CreateRuntimeStartInfo_UsesAirAppRuntimeAndRequesterPid()
{
diff --git a/LanMountainDesktop.Tests/AirAppRuntimeLifecycleServiceTests.cs b/LanMountainDesktop.Tests/AirAppRuntimeLifecycleServiceTests.cs
index 4a71521..4cc8183 100644
--- a/LanMountainDesktop.Tests/AirAppRuntimeLifecycleServiceTests.cs
+++ b/LanMountainDesktop.Tests/AirAppRuntimeLifecycleServiceTests.cs
@@ -183,7 +183,8 @@ public sealed class AirAppRuntimeLifecycleServiceTests
string sessionId,
string instanceKey,
string? sourceComponentId,
- string? sourcePlacementId)
+ string? sourcePlacementId,
+ string? targetEntryId = null)
{
StartCount++;
return _process;
diff --git a/LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs b/LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs
index 5e4b12a..b7640e0 100644
--- a/LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs
+++ b/LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs
@@ -38,6 +38,7 @@ public static class BuiltInComponentIds
public const string DesktopBilibiliHotSearch = "DesktopBilibiliHotSearch";
public const string DesktopBaiduHotSearch = "DesktopBaiduHotSearch";
public const string DesktopStcn24Forum = "DesktopStcn24Forum";
+ public const string DesktopRssReader = "DesktopRssReader";
public const string DesktopExchangeRateCalculator = "DesktopExchangeRateCalculator";
public const string DesktopWhiteboard = "DesktopWhiteboard";
public const string DesktopBlackboardLandscape = "DesktopBlackboardLandscape";
diff --git a/LanMountainDesktop/ComponentSystem/ComponentRegistry.cs b/LanMountainDesktop/ComponentSystem/ComponentRegistry.cs
index cd8c9a1..4cd4382 100644
--- a/LanMountainDesktop/ComponentSystem/ComponentRegistry.cs
+++ b/LanMountainDesktop/ComponentSystem/ComponentRegistry.cs
@@ -307,6 +307,18 @@ public sealed class ComponentRegistry
MinHeightCells: 4,
AllowStatusBarPlacement: false,
AllowDesktopPlacement: true),
+ new DesktopComponentDefinition(
+ BuiltInComponentIds.DesktopRssReader,
+ "RSS Reader",
+ "Rss",
+ "Info",
+ MinWidthCells: 8,
+ MinHeightCells: 4,
+ AllowStatusBarPlacement: false,
+ AllowDesktopPlacement: true,
+ ResizeMode: DesktopComponentResizeMode.Free,
+ Description: "A synchronized RSS and Atom reading inbox.",
+ DescriptionLocalizationKey: "component.rss_reader.description"),
new DesktopComponentDefinition(
BuiltInComponentIds.DesktopExchangeRateCalculator,
"Exchange Rate Converter",
diff --git a/LanMountainDesktop/LanMountainDesktop.csproj b/LanMountainDesktop/LanMountainDesktop.csproj
index 40d88de..6cb23c7 100644
--- a/LanMountainDesktop/LanMountainDesktop.csproj
+++ b/LanMountainDesktop/LanMountainDesktop.csproj
@@ -75,6 +75,7 @@
+
diff --git a/LanMountainDesktop/Localization/en-US.json b/LanMountainDesktop/Localization/en-US.json
index efc1482..0f4f1e1 100644
--- a/LanMountainDesktop/Localization/en-US.json
+++ b/LanMountainDesktop/Localization/en-US.json
@@ -1515,5 +1515,62 @@
"settings.general.back_to_windows_fluent_icon_desc": "Search and choose a built-in Fluent icon for the left icon slot.",
"settings.general.back_to_windows_icon_text_header": "Text icon",
"settings.general.back_to_windows_icon_text_desc": "Enter up to four characters to display as the left icon.",
- "settings.general.back_to_windows_fluent_icon_search_placeholder": "Search icon"
+ "settings.general.back_to_windows_fluent_icon_search_placeholder": "Search icon",
+ "component.rss_reader": "RSS Reader",
+ "component.rss_reader.description": "A synchronized RSS and Atom reading inbox.",
+ "rss.empty": "Import OPML or add your first RSS source",
+ "rss.latest_articles": "Latest articles",
+ "rss.refresh": "Refresh",
+ "rss.refresh_failed": "Refresh failed",
+ "rss.refreshing": "Refreshing...",
+ "rss.updated": "Updated",
+ "rss.mark_all_read": "Mark all read",
+ "rss.open_reader": "Open reader",
+ "rss.unread_count": "{0} unread",
+ "rss.all_articles": "All articles",
+ "rss.unread": "Unread",
+ "rss.favorites": "Favorites",
+ "rss.favorite": "Favorite",
+ "rss.favorited": "Favorited",
+ "rss.open_original": "Open original",
+ "rss.select_article": "Select an article",
+ "rss.article_placeholder": "Your RSS articles will appear here.",
+ "rss.status_counts": "{0} articles · {1} sources",
+ "rss.add_source": "Add source",
+ "rss.edit": "Edit",
+ "rss.edit_source": "Edit RSS source",
+ "rss.delete": "Delete",
+ "rss.delete_source": "Delete RSS source",
+ "rss.delete_source_confirm": "Delete {0}?",
+ "rss.cancel": "Cancel",
+ "rss.save": "Save",
+ "rss.enabled": "Enabled",
+ "rss.keep_favorites": "Keep favorited articles",
+ "rss.name": "Name",
+ "rss.folder": "Folder",
+ "rss.source": "Source",
+ "rss.all_sources": "All sources",
+ "rss.unread_first": "Show unread entries first",
+ "rss.entry_count": "Number of entries",
+ "rss.instance_settings_description": "These display options apply only to this component instance.",
+ "rss.feed_url": "Feed URL",
+ "rss.optional_name": "Optional custom name",
+ "rss.optional_folder": "Optional folder",
+ "rss.probe_add": "Probe and add",
+ "rss.checking_feed": "Checking feed...",
+ "rss.import_opml": "Import OPML",
+ "rss.export_opml": "Export OPML",
+ "rss.import_result": "Imported {0}, skipped {1}, failed {2}.",
+ "rss.exported": "OPML exported.",
+ "rss.settings": "RSS settings",
+ "rss.refresh_interval": "Refresh interval",
+ "rss.refresh_interval_minutes": "Refresh interval (minutes)",
+ "rss.minutes": "{0} minutes",
+ "rss.manual_only": "Manual only",
+ "rss.load_remote_images": "Load remote images",
+ "rss.air_app": "Air APP",
+ "rss.just_now": "Just now",
+ "rss.minutes_ago": "{0} min ago",
+ "rss.hours_ago": "{0} hr ago",
+ "rss.short_date_format": "MMM d"
}
diff --git a/LanMountainDesktop/Localization/zh-CN.json b/LanMountainDesktop/Localization/zh-CN.json
index 0e55a90..4b9ebdb 100644
--- a/LanMountainDesktop/Localization/zh-CN.json
+++ b/LanMountainDesktop/Localization/zh-CN.json
@@ -1470,5 +1470,62 @@
"settings.update.transfer_controls_description": "暂停正在运行的下载,从保存的状态恢复,或取消并清除待处理的更新文件。",
"settings.update.transfer_controls_title": "传输控制",
"settings.update.type_reinstall": "重新安装",
- "settings.update.update_type_label": "更新类型"
+ "settings.update.update_type_label": "更新类型",
+ "component.rss_reader": "RSS 阅读器",
+ "component.rss_reader.description": "在组件与轻应用之间同步的 RSS 与 Atom 阅读收件箱。",
+ "rss.empty": "导入 OPML 或添加第一个 RSS 源",
+ "rss.latest_articles": "最新文章",
+ "rss.refresh": "刷新",
+ "rss.refresh_failed": "刷新失败",
+ "rss.refreshing": "正在刷新...",
+ "rss.updated": "已更新",
+ "rss.mark_all_read": "全部标为已读",
+ "rss.open_reader": "进入阅读器",
+ "rss.unread_count": "{0} 篇未读",
+ "rss.all_articles": "全部文章",
+ "rss.unread": "未读",
+ "rss.favorites": "收藏",
+ "rss.favorite": "收藏",
+ "rss.favorited": "已收藏",
+ "rss.open_original": "打开原文",
+ "rss.select_article": "选择一篇文章",
+ "rss.article_placeholder": "RSS 文章正文将在这里显示。",
+ "rss.status_counts": "{0} 篇文章 · {1} 个订阅源",
+ "rss.add_source": "添加订阅源",
+ "rss.edit": "编辑",
+ "rss.edit_source": "编辑 RSS 订阅源",
+ "rss.delete": "删除",
+ "rss.delete_source": "删除 RSS 订阅源",
+ "rss.delete_source_confirm": "确定删除“{0}”吗?",
+ "rss.cancel": "取消",
+ "rss.save": "保存",
+ "rss.enabled": "启用此订阅源",
+ "rss.keep_favorites": "保留已收藏文章",
+ "rss.name": "名称",
+ "rss.folder": "文件夹",
+ "rss.source": "订阅源",
+ "rss.all_sources": "全部订阅源",
+ "rss.unread_first": "未读文章优先显示",
+ "rss.entry_count": "显示文章数量",
+ "rss.instance_settings_description": "这些显示选项仅应用于当前组件实例。",
+ "rss.feed_url": "订阅地址",
+ "rss.optional_name": "可选的自定义名称",
+ "rss.optional_folder": "可选的文件夹",
+ "rss.probe_add": "检测并添加",
+ "rss.checking_feed": "正在检测订阅源...",
+ "rss.import_opml": "导入 OPML",
+ "rss.export_opml": "导出 OPML",
+ "rss.import_result": "成功导入 {0} 个,跳过 {1} 个,失败 {2} 个。",
+ "rss.exported": "OPML 已导出。",
+ "rss.settings": "RSS 设置",
+ "rss.refresh_interval": "刷新间隔",
+ "rss.refresh_interval_minutes": "刷新间隔(分钟)",
+ "rss.minutes": "{0} 分钟",
+ "rss.manual_only": "仅手动刷新",
+ "rss.load_remote_images": "加载远程图片",
+ "rss.air_app": "轻应用",
+ "rss.just_now": "刚刚",
+ "rss.minutes_ago": "{0} 分钟前",
+ "rss.hours_ago": "{0} 小时前",
+ "rss.short_date_format": "M 月 d 日"
}
diff --git a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs
index cb344ad..08871ab 100644
--- a/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs
+++ b/LanMountainDesktop/Models/ComponentSettingsSnapshot.cs
@@ -71,6 +71,12 @@ public sealed class ComponentSettingsSnapshot
public string Stcn24ForumSourceType { get; set; } = Stcn24ForumSourceTypes.LatestCreated;
+ public string RssReaderSourceId { get; set; } = string.Empty;
+
+ public bool RssReaderUnreadFirst { get; set; } = true;
+
+ public int RssReaderDisplayCount { get; set; } = 20;
+
public List? OfficeRecentDocumentsEnabledSources { get; set; }
// 智教Hub组件配置
diff --git a/LanMountainDesktop/Services/AirAppLauncherService.cs b/LanMountainDesktop/Services/AirAppLauncherService.cs
index b7f1567..ce3a687 100644
--- a/LanMountainDesktop/Services/AirAppLauncherService.cs
+++ b/LanMountainDesktop/Services/AirAppLauncherService.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using LanMountainDesktop.ComponentSystem;
using LanMountainDesktop.Shared.IPC;
using LanMountainDesktop.Shared.IPC.Abstractions.Services;
+using LanMountainDesktop.Services.RssReader;
namespace LanMountainDesktop.Services;
@@ -15,12 +16,15 @@ public interface IAirAppLauncherService
void OpenWorldClock(string sourceComponentId, string? sourcePlacementId);
void OpenWhiteboard(string componentId, string? sourcePlacementId);
+
+ void OpenRssReader(string componentId, string? sourcePlacementId, string? targetEntryId = null);
}
internal sealed class AirAppLauncherService : IAirAppLauncherService
{
public const string WorldClockAppId = "world-clock";
public const string WhiteboardAppId = "whiteboard";
+ public const string RssReaderAppId = "rss-reader";
private const int RuntimeIpcRetryCount = 4;
@@ -48,17 +52,30 @@ internal sealed class AirAppLauncherService : IAirAppLauncherService
_ = OpenAsync(WhiteboardAppId, componentId, sourcePlacementId);
}
+ public void OpenRssReader(string componentId, string? sourcePlacementId, string? targetEntryId = null)
+ {
+ AppLogger.Info("AirAppLauncher", $"RSS Reader Air APP requested. EntryId='{targetEntryId ?? string.Empty}'.");
+ if (!string.IsNullOrWhiteSpace(targetEntryId))
+ {
+ using var service = new RssReaderService();
+ service.SetPendingEntryId(targetEntryId);
+ }
+ _ = OpenAsync(RssReaderAppId, componentId, sourcePlacementId, targetEntryId);
+ }
+
internal static AirAppOpenRequest BuildOpenRequest(
string appId,
string? sourceComponentId,
string? sourcePlacementId,
- int requesterProcessId)
+ int requesterProcessId,
+ string? targetEntryId = null)
{
return new AirAppOpenRequest(
appId.Trim(),
string.IsNullOrWhiteSpace(sourceComponentId) ? null : sourceComponentId.Trim(),
string.IsNullOrWhiteSpace(sourcePlacementId) ? null : sourcePlacementId.Trim(),
- requesterProcessId);
+ requesterProcessId,
+ string.IsNullOrWhiteSpace(targetEntryId) ? null : targetEntryId.Trim());
}
internal static string BuildSingleInstanceKey(string appId, string? sourceComponentId, string? sourcePlacementId)
@@ -68,15 +85,19 @@ internal sealed class AirAppLauncherService : IAirAppLauncherService
{
return $"{normalizedAppId}:clock-suite:global";
}
+ if (string.Equals(normalizedAppId, RssReaderAppId, StringComparison.OrdinalIgnoreCase))
+ {
+ return $"{normalizedAppId}:global";
+ }
var normalizedComponentId = string.IsNullOrWhiteSpace(sourceComponentId) ? "none" : sourceComponentId.Trim();
var normalizedPlacementId = string.IsNullOrWhiteSpace(sourcePlacementId) ? "none" : sourcePlacementId.Trim();
return $"{normalizedAppId}:{normalizedComponentId}:{normalizedPlacementId}";
}
- private static async Task OpenAsync(string appId, string sourceComponentId, string? sourcePlacementId)
+ private static async Task OpenAsync(string appId, string sourceComponentId, string? sourcePlacementId, string? targetEntryId = null)
{
- var request = BuildOpenRequest(appId, sourceComponentId, sourcePlacementId, Environment.ProcessId);
+ var request = BuildOpenRequest(appId, sourceComponentId, sourcePlacementId, Environment.ProcessId, targetEntryId);
try
{
var result = await SendOpenRequestAsync(request).ConfigureAwait(false);
diff --git a/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs b/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs
index f2fd5b6..9ee1ed1 100644
--- a/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs
+++ b/LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs
@@ -263,6 +263,11 @@ public static class DesktopComponentEditorRegistryFactory
nameof(ComponentSettingsSnapshot.Stcn24ForumSourceType)
]
})),
+ [BuiltInComponentIds.DesktopRssReader] = new(
+ BuiltInComponentIds.DesktopRssReader,
+ context => new RssReaderComponentEditor(context),
+ preferredWidth: 480d,
+ preferredHeight: 480d),
[BuiltInComponentIds.DesktopZhiJiaoHub] = new(
BuiltInComponentIds.DesktopZhiJiaoHub,
context => new ZhiJiaoHubComponentEditor(context),
diff --git a/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs b/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs
index aca32c1..3653f28 100644
--- a/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs
+++ b/LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs
@@ -452,6 +452,12 @@ public sealed class DesktopComponentRuntimeRegistry
BuiltInComponentIds.DesktopStcn24Forum,
"component.stcn24_forum",
() => new Stcn24ForumWidget()),
+ new DesktopComponentRuntimeRegistration(
+ BuiltInComponentIds.DesktopRssReader,
+ "component.rss_reader",
+ (Func)(context =>
+ new RssReaderWidget(context.ComponentSettingsAccessor, context.PlacementId)),
+ cornerRadiusResolver: (Func?)null),
new DesktopComponentRuntimeRegistration(
BuiltInComponentIds.DesktopExchangeRateCalculator,
"component.exchange_rate_converter",